Display the same DIV over multiple elements - javascript

I'm working on an ecommerce site for a client using Business Catalyst.
On their "Menu" page, they would like to display an "Out of Stock" DIV over the images of all out-of-stock products.
The DIV should be triggered by BC's proprietary content tag, {tag_instock}.
When {tag_instock} is 0, div.nostock should be displayed on all products that are out-of-stock.
At the moment, it only displays over one product that is out-of-stock rather than all products.
HTML:
<ul class="product-images">
<div id="nostock" class="nostock" style="display: none;"><h2>Out of Stock</h2></div>
<li>img_one</li>
<li>img_two</li>
<li>img_three</li>
</ul>
SCRIPT:
$(document).ready(function() {
var stock = "{tag_instock}";
if (stock == 0) {
document.getElementById('nostock').style.display = "block"
};
});
I'm not quite clear about using jquery vs. javascript. Which would be better suited to this solution?
Please let me know if I need to elaborate.
Any help is greatly appreciated.
Thank you.

I simulate stock value with data attribute for demo purposes...tell me if this works for you, here's a Fiddle
$(function() {
$('li').each(function() {
// var stock = "{tag_instock}";
var stock = $(this).data('stock');
if (stock == 0) {
$(this).append('<div class="nostock">Out of Stock</div>');
}
if (stock > 0) {
$(this).append('<div class="instock">In Stock '+stock+'</div>');
}
});
});
I overdo it a little, added instock and instock values aside, Fiddle updated.

If the three images are always the same, I would combine them into a single image. If you do that, then you can create a CSS class that overlays the image using a content property. By dynamically adding the class to the div's in question, you achieve the affect you want.
The class looks like this:
.no-stock-image:after {
content: url(images/out-of-stock.png);
position: absolute;
top: 10px;
left: -10px;
}
Obviously you'll have to adjust the positioning.

It sounds to me like you should use the following HTML:
<ul class="product-images">
<li><span class="nostock" style="display: none;">Out of Stock</span>img_one</li>
<li><span class="nostock" style="display: none;">Out of Stock</span>img_two</li>
<li><span class="nostock" style="display: none;">Out of Stock</span>img_three</li>
</ul>
Then use CSS like:
.no-stock {
position: absolute;
top: Xpx;
left: Xpx;
width: Xpx;
height: Xpx
background-color: #eee;
}
Adjusting the X's to suit.

Related

Add & remove classes with fewer lines of code

I'm trying to learn how to shorten my jQuery code. Any suggestions or tips would be awesome:
jQuery(document).ready(function($){
$('#checkout_timeline #timeline-4').click(function() {
if ($('#checkout_timeline #timeline-4').hasClass('active')) {
$('#checkout-payment-container').addClass('cpc-visible');
}
});
$('#checkout_timeline #timeline-1, #checkout_timeline #timeline-2, #checkout_timeline #timeline-3').click(function() {
$('#checkout-payment-container').removeClass('cpc-visible');
});
});
To avoid clutter, please find the working version here:
My JSFiddle Code
I know I can use .show() and .hide() but due to other CSS considerations I want to apply .cpc-visible.
There are a handful of things you can improve here. First, you're over-specifying. Ids are unique. No need to select #checkout_timeline #timeline-4 when just #timeline-4 will do. But why even have ids for each li? You can reference them by number using the :nth-child(n) selector. Or better yet, you've already given them application-specific class names like billing, shipment, and payment. Use those! Let's simplify the original content to:
<ul id="checkout_timeline">
<li class='billing'>Billing</li>
<li class='shipping'>Shipping</li>
<li class='confirm'>Confirm</li>
<li class='payment active'>Payment</li>
</ul>
<div id='checkout-payment-container' class='cpc-visible'>
This is the container to show and hide.
</div>
Notice I left the active class, and indeed further initialized the checkout
div with cpc-visible to mirror the payment-is-active condition. Usually I would keep HTML as simple as possible and put "starting positions" initialization in code. But "in for a penny, in for a pound." If we start with payment active, might as well see that decision through, and start the dependent div in a consistent state.
Now, revised JavaScript:
jQuery(document).ready(function($) {
$('#checkout_timeline li').click(function() {
// make clicked pane active, and the others not
$('#checkout_timeline li').removeClass('active');
$(this).addClass('active');
// show payment container only if payment pane active
var paymentActive = $(this).hasClass('payment');
$('#checkout-payment-container').toggleClass('cpc-visible', paymentActive);
});
});
This code is much less item-specific. It doesn't try to add separate click handlers for different tabs/panes. They all get the same handler, which makes a uniform set of decisions. First, that whichever pane is clicked, make it active and the others not active. It does this by removing all active classes, then putting active on just the currently selected pane. Second, it asks "is the current pane the payment pane?" And it uses the toggleClass API to set the cpc-visible class accordingly. Often such "set class based on a boolean condition" logic is simpler and more reliable than trying to pair appropriate addClass and removeClass calls.
And we're done. Here's a JSFiddle that shows this in action.
Try this : You can user jquery selector with timeline and active class to bind click event handler where you can add required class. Same selector but not having active class to remove class.
This will be useful when you add / remove elements and will be more flexible.
jQuery(document).ready(function($){
$('#checkout_timeline .timeline.active').click(function() {
$('#checkout-payment-container').addClass('cpc-visible');
});
$('#checkout_timeline .timeline:not(.active)').click(function() {
$('#checkout-payment-container').removeClass('cpc-visible');
});
});
JSFIddle
Here is one of the ways, you can shorten this code by using :not(). Also its better to use elements than to reference and get them via JQuery always.
jQuery(document).ready(function($) {
var showHideContainer = $('#checkout-payment-container');
$('#checkout_timeline .timeline.active').click(function() {
showHideContainer.addClass('cpc-visible');
});
$('#checkout_timeline .timeline:not(.payment)').click(function() {
showHideContainer.removeClass('cpc-visible');
});
});
try this code its working fine with fiddle
$('.timeline').click(function() {
if ($(this).hasClass('active') && $(this).attr("id") == "timeline-4")
$('#checkout-payment-container').addClass('cpc-visible');
else
$('#checkout-payment-container').removeClass('cpc-visible');
});
This would of been my approach cause you still have to add/remove the active class between each li.
jQuery(document).ready(function($) {
$('ul li').click(function() {
$('ul li.active').removeClass('active');
$(this).closest('li').addClass('active');
k();
});
var k = (function() {
return $('#timeline-4').hasClass('active') ? $('#checkout-payment-container').addClass('cpc-visible') : $('#checkout-payment-container').removeClass('cpc-visible');
});
});
#checkout-payment-container {
float: left;
display: none;
background: red;
color: white;
height: 300px;
width: 305px;
padding: 5px;
}
ul {
list-style: none;
width: 100%;
padding: 0 0 20px 0px;
}
li {
float: left;
padding: 5px 11px;
margin-right: 5px;
background: gray;
color: white;
cursor: pointer;
}
li.active {
background: black;
}
.cpc-visible {
display: block !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="checkout_timeline">
<li id='timeline-1' class='timeline billing'>Billing</li>
<li id='timeline-2' class='timeline shipping'>Shipping</li>
<li id='timeline-3' class='timeline confirm'>Confirm</li>
<li id='timeline-4' class='timeline payment'>Payment</li>
</ul>
<div id='checkout-payment-container'>
This is the container to show and hide.
</div>
Your code look great, i would have written it the same.
bit sure how much it helps but if you like, you can use inline if like this:
$(document).ready(function(){
$('#B').click(function() { (!$('#B').hasClass('active')) ?
$('#A').addClass('active') : ''; });
$('#C').click(function() { $('#A').removeClass('active'); });
});
Link for a live example:
jsFiddle

Apply unique styles to each <li> in an ng-repeat list in Angular

I am very new to angular and I am having some difficulty wrapping my head around how to handle certain things "the Angular way". Please forgive my ignorance in this post.
I currently have 6 list items that are created by hitting a data source and using ng-repeat.
<ul>
<li ng-repeat="vote in votes" ng-click="vote.Score = vote.Score + 1">
{{ vote.Id | covertToName }} has a score of {{ vote.Score }}
</li>
</ul>
Each of these list items has a "progress bar" below it which is simply a absolutely positioned :after psuedo element. My aim is to increase the width of the progress bar's :after psuedo element when you click on the list item to give you a visual display of the number of votes each element has.
I need a way to apply a custom style (width:) to each of the list items created by the ng-repeat when a user clicks on a list item. For example, if a user clicks on John Doe and his Score is currently at 50, I need his progress bar to assume a width of 51px as well as apply the score pixel width to all other list items.
Any direction is greatly appreciated.
Thank You!
Edit: I am using SCSS and I have no control over the JSON data source.
If you're using a CSS preprocessor like SASS you can easily achieve this by using ng-class="progress". progress would hold a string like progress-51.
The SASS-code
$class-slug: progress !default
#for $i from 0 through 100
.#{$class-slug}-#{$i}:after
width: 0px + $i
would emit
.progress-0:after {
width: 0px;
}
.progress-1:after {
width: 1px;
}
...
.progress-100:after {
width: 100px;
}
You can try as below
li:first-child:after { /*styles*/ }
li:second-child:after { /*styles*/ }
li:third-child:after { /*styles*/ }
li:fourth-child:after { /*styles*/ }
li:fifth-child:after { /*styles*/ }
li:sixth-child:after { /*styles*/ }
If you need exact pixels based of values I dont think classes is really useful since you don't know what element need what style. Perhaps you can use inline styles for this even though it is not best practise.
Example:
<ul>
<li ng-repeat="vote in votes" ng-click="vote.Score = vote.Score + 1">
<span style="width:{{vote.score}}px;>{{ vote.Id | covertToName }} has a score of {{ vote.Score }}</span>
</li>
</ul>
mm.. u can create attrib in object votes, like this:
var votes = [{Id:0,Score:0,width:"first"},{Id:1,Score:0,width:"second"},{Id:2,Score:0,width:"third"}];
And then u can use ng-class to do a unique style each li:
<ul>
<li ng-repeat="vote in votes" ng-class="vote.width" vote.ng-click="vote.Score = vote.Score + 1">
{{ vote.Id | covertToName }} has a score of {{ vote.Score }}
</li>
</ul>
and need define this styles:
.second {
width: 50%;
background:red;
}
.first {
width: 20%;
background: blue;
}
.third {
width: 30%;
background: orange;
}

jQuery filter - items not re-organising (isotope)

I have a page that has a structure like this:
<div id="k2Container"> <!--sets K2 Category Layout-->
<div class="itemList"> <!--Contains the items loaded-->
<div id="itemListLeading"></div> <!--contains one tile that is always first-->
<div id="itemListPrimary"></div> <!--contains the rest of the tiles-->
</div>
</div>
The tile within itemListLeading has a class of 'itemContainer blue' and the tile(s) within itemListPrimary have a class of 'itemContainer red'. The filter below filters the items accordingly, but the grid isn't responsive and the tiles don't re-organise.
<ul id="filters">
<li>All sizes</li>
<li>Wide</li>
<li>High</li>
<li>Small</li>
</ul>
<script>
$(function() {
var $container = $('#k2Container');
$container.isotope({
itemSelector: '.itemContainer',
masonry: {
columnWidth: '#blank-item'
}
});
$('#filters').on('click', 'a', function() {
var selector = $(this).data('filter');
$container.isotope({
filter: selector,
layoutMode: 'masonry'
});
});
});
</script>
The masonry configuration in another location sets the container widths etc, which I'm guessing I need to call once the items have been filtered; however I'm not sure how. This can be provided upon request, I just don't want to bulk this out with too much script.
Update
I think I've found the problem, however I'm not sure how to amend it. When the page is loaded, the grid is fine. The styling for the tile is as follows.
style="position: absolute; left: 728px; top: 0px; width: 354px;"
Obviously the 'left: 364px' increments for each tile, as does the 'top: 0px' for each row, but when the filter is applied the styling is this (for the same tile):
style="position: absolute; left: 728px; top: 0px; width: 354px; transform: translate3d(354px, 0px, 0px);"
If I remove the '354px' from the translate 3d, the tiles realign next to each other. Any ideas as to why this is being generated?
And why you don't want create one parent element for grid, with items as childrens? Then you may do filtering with fixed first item. Add a class "item-lead" for first element, which must be fixed, and add selector+=", .item-lead"; after var selector = $(this).data('filter');.
Working example, forked on isotope default example
Excuse me if I do not fully understand your question, but I think my method is easier than to divide the grid into two parts. ;)

Scrolling a DIV to Specific Location

There is a plethora of similar questions around but none of them seem to be looking for what I'm looking for, or else none of the answers are useful for my purposes.
The jsfiddle: http://jsfiddle.net/tumblingpenguin/9yGCf/4/
The user will select an option and the page will reload with their option applied. What I need is for the "option list" DIV to be scrolled down to the selected option such that it is in the center of the option list.
The HTML...
<div id="container">
<a href="#">
<div class="option">
Option 1
</div>
</a>
<!-- other options -->
<a href="#">
<div class="option selected"> <!-- scroll to here -->
Option 4
</div>
<!-- other options -->
<a href="#">
<div class="option">
Option 7
</div>
</a>
</div>
The selected option is marked with the selected class. I need to somehow scroll the DIV down to the selected option.
The CSS...
#container {
background-color: #F00;
height: 100px;
overflow-x: hidden;
overflow-y: scroll;
width: 200px;
}
a {
color: #FFF;
text-decoration: none;
}
.option {
background-color: #c0c0c0;
padding: 5px;
width: 200px;
}
.option:hover {
background-color: #ccc;
}
.selected {
background-color: #3c6;
}
I've seen this done on other websites so I know it's possible—I just haven't a clue where to begin with it.
P.S. jQuery solutions are acceptable.
Something like this http://jsfiddle.net/X2eTL/1/:
// On document ready
$(function(){
// Find selected div
var selected = $('#container .selected');
// Scroll container to offset of the selected div
selected.parent().parent().scrollTop(selected[0].offsetTop);
});
Without the jQuery (put this at the bottom of the < body > tag:
// Find selected div
var selected = document.querySelector('#container .selected');
// Scroll container to offset of the selected div
selected.parentNode.parentNode.scrollTop = selected.offsetTop;
demo: http://jsfiddle.net/66tGt/
Since you said JQuery answers are acceptable, here's an example of what you're looking for:
$('body, html').animate({ scrollTop: div.offset().top-210 }, 1000);
Replace div for whatever element you want to scroll to.
Here is one possible solution that may work for you:
Demo Fiddle
JS:
$('#container').scrollTop( $('.selected').position().top );
Take a look at this fiddle : http://jsfiddle.net/9yGCf/8/
As requested it scrolls to the middle of the div (you can change the offset by however much you want to make little adjustments). I would probably suggest setting either a line height with some padding and whatnot and then do the math to change the offset that I have at -40 so that it does put it in the middle.
But I used jquery and came up with this quick little code... also added some code to change the selected option
$('.option').click(function(){
$('.selected').removeClass('selected');
$(this).addClass('selected');
$(this).parent().parent().scrollTop(selected[0].offsetTop - 40);
});
This magical API will automatically scroll to the right position.
element.scrollIntoView({ block: 'center' })
See more details:
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView

How to increase the height of my dropdown?

I have a dropdown in HTML. When I hover on it, it expands. I added a new entry in the dropdown, and when I hover on it, I want my new entry visible completely (I added Comp3 in dropdown. I can see the upper part of it, but not completely Comp3). I tried various things like giving height to divs, increasing the height of the component in css, but nothing helped. Viewing the source code of that in the browser, this is the small code snippet of that particular dropdown:
<div class="optionsDropDown">
<p class="optionsDropDown collapseTrigger" id="userMenu">
Hello<em> User </em><span class="closed"></span>
</p>
<ul class="optionsDropDown collapseContent closed" name="userMenu">
<li>
<a class="optionsDropDown" href="javascript:showHelp();">
<span id="0">Comp1</span>
</a>
</li>
<li>
<a class="optionsDropDown" href="myAction.do?actionCode=3&page=controlPanel" target="view">
<span id="1">Comp3</span>
</a>
</li>
</ul>
</div>
Below is the javascript function that expands the dropdown:
$.fn.openMenu = function(menuContent){
$(menuContent).slideDown(200,function() {
$(menuContent).children().fadeTo('fast',1);
});
$('span', this).removeClass('closed');
};
And here is the dropdown class:
div.optionsDropDown {
float: right;
font-size: 11px;
height: 25px;
margin: 12px 32px 0 0;
position: absolute;
top: 0px;
right: 10px;
width: 120px;
z-index: 10000;
}
Please let me know if somehow height can be increased. Thanks in advance.
I believe your <div> and <ul> heights needs to be set to auto and the heights of each <li> needs to be adjusted.
Often times CSS becomes the practice of hit or miss when dealing with issues like these. First set everything to auto then systematically experiment with every permutation.
Good luck!

Categories

Resources