Create the list with limited elements inside - javascript

I need to create ul with a limit of 5 li's inside. If it goes more then 5 elements - create new ul with the same limitations. And so on and on. Here is the start point I made:
$(function(){
var $container = $('.container'),
el = 5,
i;
newUl = $('<ul />')
for(i=0; i < el; i++){
$container.append(newUl)
$('<li />', { html : i }).appendTo(newUl)
}
})
* {
box-sizing: border-box;
}
body {
background: #f2f2f2;
}
.wrapper {
display: table;
margin: 0 auto;
padding: 10px;
max-width: 600px;
width: 100%;
height: 100vh;
border: 2px solid rgba(0, 0, 0, 0.2);
}
.wrapper .container {
display: table-cell;
vertical-align: bottom;
}
.wrapper ul {
background: #c0c0c0;
border: 1px solid #333;
font-size: 0;
}
.wrapper ul:nth-of-type(odd) {
direction: rtl;
}
.wrapper ul li {
display: inline-block;
font-size: 16px;
width: 20%;
padding: 10px;
border: 1px solid #333;
text-align: center;
direction: rtl;
}
.status {
position: fixed;
left: 0;
top: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="container">
</div>
</div>
<div class="status"></div>
Any advices how to do this?

You can use the modulus operator % to determine when you have reached the max, and then you need to create a new jQuery for your new ul, and append it.
$(function(){
var $container = $('.container'),
el = 10,
max = 5,
i;
var newUl;
for(i=0; i < el; i++){
if(i%max==0) {
newUl = $('<ul/>');
$container.append(newUl);
}
$('<li />', { html : i }).appendTo(newUl)
}
});
* {
box-sizing: border-box;
}
body {
background: #f2f2f2;
}
.wrapper {
display: table;
margin: 0 auto;
padding: 10px;
max-width: 600px;
width: 100%;
height: 100vh;
border: 2px solid rgba(0, 0, 0, 0.2);
}
.wrapper .container {
display: table-cell;
vertical-align: bottom;
}
.wrapper ul {
background: #c0c0c0;
border: 1px solid #333;
font-size: 0;
}
.wrapper ul:nth-of-type(odd) {
direction: rtl;
}
.wrapper ul li {
display: inline-block;
font-size: 16px;
width: 20%;
padding: 10px;
border: 1px solid #333;
text-align: center;
direction: rtl;
}
.status {
position: fixed;
left: 0;
top: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="container">
</div>
</div>
<div class="status"></div>

I'm not quite following your example, so forgive me that I've just started fresh here. The first loop and the 12 on line 2 is just to generate a list of fake data to work with. Test it with 0, less than 5, multiples of 5, and 1+ a multiple of 5 just to make sure it works.
var items = [];
for(var i=0; i<12; i++) {
items.push("item " + i.toString());
}
var subItems = items.splice(0, 5);
var div = $("<div>").get(0);
while(subItems.length > 0) {
var ul = $("<ul>").get(0);
div.appendChild(ul);
for(var i=0; i<subItems.length; i++) {
ul.appendChild( $("<li>").text(subItems[i]).get(0) );
}
subItems = items.splice(0, 5);
}
You can paste this into the console to see the results. Just add console.log(div) at the end.
This will create a div with n number of ul tags, each having 5 li's (or less depending on the data)
Change line 6 to point to your div tag. And I'm not sure we can tell from your example where the data is supposed to come from so you'll need to change items and line 11 accordingly.

Related

Add line numbers to text area using javascript

I wanted to add line numbering to a textarea.
I get the number of lines by using
textAreaElement.value.split("\n").length;
and maintain a div with span elements that use the count as content on before to add line numbers.
.line-number {
width: 100%;
display: block;
text-align: right;
line-height:1.5em;
border-bottom: thin;
font-family:'CascadiaCode Nerd Font', monospace;
font-size: 2rem;
color: #fff;
opacity: 0.8;
padding: 0 0.4em;
}
.line-number::before {
counter-increment: line;
content: counter(line);
font-size: 1em;
user-select: none;
}
However this has a fixed height, I want to implement this for a text area with word wrap (no horizontal scrollbar), where every line can technically have multiple lines terminated by a "\n".
My line of thought was to prepare an array of heights for each lines but I have no idea how to get the height of each separate line.
update:
I switched to an editable div, but i want my line number to be of the same height as its corresponding div.
const lineEnum = {
state: false,
count: 0,
gutter: document.getElementsByClassName("line-numbers")[0],
update: (box) => {
let delta = box.children.length - lineEnum.count;
if (box.children.length == 0) delta++;
console.log({
delta: delta,
count: lineEnum.count,
length: box.children.length,
});
if (delta > 0 && lineEnum.state) {
const frag = document.createDocumentFragment();
while (delta > 0) {
const line_number = document.createElement("span");
line_number.className = "line-num";
frag.appendChild(line_number);
lineEnum.count++;
delta--;
}
lineEnum.gutter.appendChild(frag);
} else {
if (lineEnum.count + delta === 0) delta++;
while (delta < 0 && lineEnum.gutter.lastChild) {
lineEnum.gutter.removeChild(lineEnum.gutter.lastChild);
lineEnum.count--;
delta++;
}
}
},
init: (box) => {
if (lineEnum.state) return;
lineEnum.state = true;
lineEnum.update(box);
},
remove: (box) => {
if (!lineEnum.state || !lineEnum.gutter.firstChild) return;
lineEnum.gutter.innerHtml = "";
lineEnum.state = false;
},
};
const callback = (mutationList, observer) => {
let mutation = mutationList[mutationList.length - 1];
if (mutation.type === "childList") {
console.log(mutation);
lineEnum.update(mutation.target);
}
};
const observer = new MutationObserver(callback);
const config = { childList: true };
const editor = document.getElementsByClassName("code-input")[0];
observer.observe(editor, config);
lineEnum.init(editor);
.window-body{
position: fixed;
height: 100%;
top: 25px;
width: 100%;
display: flex;
}
.line-numbers {
width: 5em;
padding: 0;
height: 100%;
word-break: break-all;
overflow: hidden;
display: inline-block;
counter-reset: line;
background-color: gray;
opacity: 0.8;
}
.line-num {
width: 100%;
display: block;
text-align: middle;
line-height:1.5em;
border-bottom: thin;
font-family:'Arial', monospace;
font-size: 2rem;
color: #fff;
opacity: 0.8;
padding: 0 1em;
}
.line-num::before {
counter-increment: line;
content: counter(line);
font-size: 1em;
user-select: none;
}
.code-input{
margin: 0;
border: 0;
padding: 0;
outline: 0;
list-style: none;
display: inline-block;
flex-grow: 1;
height: 100%;
word-break: break-all;
overflow: hidden;
border:none;
font-family:'Arial', monospace;
font-size:2rem;
background: white;
white-space:pre-wrap;
line-height:1.5em;
word-wrap: break-word;
resize:none;
}
<div class="window-body">
<div class="line-numbers"></div>
<div class="code-input" contenteditable="true"></div>
</div>
Man I wasted so much time on using javascript when css magic would just have done the trick.
Here is how I did it,
body {
background-color: #000;
height: 100vh;
width: 100vw;
margin: 0px;
}
.editor-wrapper {
height: 100vh;
width: 100vw;
overflow-y: auto;
counter-reset: line;
}
.editor{
margin: 0;
border: 0;
padding: 0;
outline: 0;
list-style: none;
height: 100%;
width: 100%;
word-wrap: break-word;
word-break: break-all;
font-size:2rem;
line-height: 1.5em;
font-feature-settings: common-ligatures;
-ms-font-feature-settings: common-ligatures;
color:rgba(255, 255, 255, 0.7);
resize:none;
}
.editor div {
padding-left: 5rem;
position: relative;
}
.editor div::before {
counter-increment: line;
content: counter(line);
font-size: 1em;
user-select: none;
width: 5rem;
text-align: right;
left: 0;
position: absolute;
}
<div class="editor-wrapper">
<div class="editor" contenteditable="true">
<div></div>
</div>
</div>
You can use a background image like so:
.lined-textarea {
background: url(http://i.imgur.com/2cOaJ.png);
background-attachment: local;
background-repeat: no-repeat;
padding-left: 35px;
padding-top: 10px;
border-color: #ccc;
font-size: 13px;
line-height: 16px;
resize: none;
}
<textarea rows="8" cols="30" class="lined-textarea"></textarea>
If it's a code block with line numbers you want then https://www.prowaretech.com/Computer/JavaScript/AddLineNumbersToPre demonstrates this well.
function addLineClass (pre) {
var lines = pre.innerText.split("\n"); // can use innerHTML also
while(pre.childNodes.length > 0) {
pre.removeChild(pre.childNodes[0]);
}
for(var i = 0; i < lines.length; i++) {
var span = document.createElement("span");
span.className = "line";
span.innerText = lines[i]; // can use innerHTML also
pre.appendChild(span);
pre.appendChild(document.createTextNode("\n"));
}
}
Along with the CSS using the essential part:
pre span.line::before {
content: counter(linecounter);
See https://jsfiddle.net/Abeeee/12cx5ruf/6/ for a running example

Vertical JavaScript Menu - Not All Subsections Displaying

Currently, I'm helping to build a website for a family member as part of a modeling club they have.
The website is at http://testindyamps.weebly.com/ .
It's a website on a host that utilizes various templates for themes (I haven't had much help so far from people on said site).
I'm not 100% sure if this ist he best place to post the question, but I thought I'd give it a shot.
The main issue is that it's utilizing a sidebar navigation where when you click the menus, it expands downward to show the subpages. In this case, not all the subpages are showing. (For example, clicking on "Articles" and then "Books" shows only the first few of a dozen or so pages.
I've tried editing the JS code itself, which so far has had no affect. I've tried editing some of the CSS, however, it doesn't seem to have an affect either.
If it helps, I can share osme of the CSS code or JS code for the site itself. Any help would be appreciated.
Thank you.
UPDATE: Added the code as requested.
Update 2: Added HTML: fixed to correct URL (using a test site instead of the "actual" site for the navigation).
jQuery(function($) {
// Mobile sidebars
$.fn.expandableSidebar = function(expandedClass) {
var $me = this;
$me.on('click', function() {
if(!$me.hasClass(expandedClass)) {
$me.addClass(expandedClass);
} else {
$me.removeClass(expandedClass);
}
});
}
// Interval loop
$.fn.intervalLoop = function(condition, action, duration, limit) {
var counter = 0;
var looper = setInterval(function(){
if (counter >= limit || $.fn.checkIfElementExists(condition)) {
clearInterval(looper);
} else {
action();
counter++;
}
}, duration);
}
// Check if element exists
$.fn.checkIfElementExists = function(selector) {
return $(selector).length;
}
// Check if desktop display
$.fn.isDesktop = function() {
return $(window).width() > 1024;
}
var briskController = {
init: function(opts) {
var base = this;
base._addClasses();
setTimeout(function(){
base._attachEvents();
}, 1000);
},
_addClasses: function() {
var base = this;
// Add fade in class to nav + logo + banner
$('body').addClass('fade-in');
// Keep subnav open if submenu item is active
$('.sidebar-nav .active').parents('.has-submenu').children('.dropdown').addClass('open');
// Add placeholder text to inputs
$('.wsite-form-sublabel').each(function(){
var sublabel = $(this).text();
$(this).prev('.wsite-form-input').attr('placeholder', sublabel);
});
},
_cloneLogin: function() {
var loginDetach = $('#member-login').clone(true);
$('.mobile-nav .wsite-menu-default > li:last-child').after(loginDetach);
},
_stickyNav: function() {
var sticky,
collapse,
uncollapse,
desktopsticky = $('body.nav-position-top.sticky-nav-on:not(.wsite-checkout-page):not(.wsite-native-mobile-editor), body.nav-position-top-right.sticky-nav-on:not(.wsite-checkout-page):not(.wsite-native-mobile-editor)').length,
mobilesticky = $('body.sticky-nav-on:not(.wsite-checkout-page):not(.wsite-native-mobile-editor)').length;
var stickyInit = function() {
if (!$.fn.isDesktop() || desktopsticky) {
// Add sticky desktop nav
sticky = new Waypoint.Sticky({
element: $('.header')[0]
});
}
if ($.fn.isDesktop() && desktopsticky) {
// Collapse header on scroll
collapse = new Waypoint({
element: $('body.nav-position-top.sticky-nav-on:not(.wsite-checkout-page):not(.wsite-native-mobile-editor)')[0],
handler: function(direction) {
$('body').addClass('collapse');
},
offset: -10
});
uncollapse = new Waypoint({
element: $('body.nav-position-top'),
handler: function(direction) {
$('body').removeClass('collapse');
},
offset: -5
});
}
}
stickyInit();
$(window).resize(function() {
if (sticky) { sticky.destroy() }
if (collapse) { collapse.destroy() }
if (uncollapse) { uncollapse.destroy() }
stickyInit();
});
},
_sidebarNav: function() {
// Fixed sidebar nav unless menu height exceeds viewport height
var sidebarCheck = function() {
if ($.fn.isDesktop() && $('body').hasClass('sticky-nav-on') && $('.header .container').height() + $('.header .contact').height() <= $(window).height() - 45) {
$('body.nav-position-sidebar .header').addClass('stuck');
}
else {
$('body.nav-position-sidebar .header').removeClass('stuck');
}
}
sidebarCheck();
$(window).resize(function() {
sidebarCheck();
});
},
_sidebarCart: function(){
$('#wsite-mini-cart').addClass('cart-init');
$('.wsite-nav-cart a').click(function() {
$('.cart-init').toggleClass('cart-visible');
});
$('.wrapper, .header').click(function() {
$('.cart-init').removeClass('cart-visible');
});
},
_attachEvents: function() {
var base = this;
// Hamburger nav toggle
$('.hamburger').on('click', function(e) {
e.preventDefault();
$('body').toggleClass('nav-open');
});
// Initialize sticky nav
base._stickyNav();
// Initialize sidebar nav
base._sidebarNav();
// Copy login
$.fn.intervalLoop('.mobile-nav #member-login', base._cloneLogin, 800, 5);
// Subnav toggle
$('li.has-submenu span.icon-caret, .dropdown-link').on('click', function() {
var $me = $(this);
if ($me.parent().hasClass('open')) {
$me.parent().removeClass('open');
$me.find('.open').removeClass('open');
}
else {
$('.open').removeClass('open');
$me.parents('.has-submenu').children('.dropdown').addClass('open');
}
setTimeout(function(){
base._sidebarNav();
}, 800);
});
// Sidebar Cart Link
$.fn.intervalLoop('.cart-init', base._sidebarCart, 1000, 5);
// Store category dropdown
$('.wsite-com-sidebar').expandableSidebar('sidebar-expanded');
// Search filters dropdown
$('#wsite-search-sidebar').expandableSidebar('sidebar-expanded');
// Init fancybox swipe on mobile
if ('ontouchstart' in window) {
$('body').on('click', 'a.w-fancybox', function() {
base._initSwipeGallery();
});
}
},
_initSwipeGallery: function() {
var base = this;
setTimeout(function(){
var touchGallery = document.getElementsByClassName('fancybox-wrap')[0];
var mc = new Hammer(touchGallery);
mc.on("panleft panright", function(ev) {
if (ev.type == "panleft") {
$("a.fancybox-next").trigger("click");
} else if (ev.type == "panright") {
$("a.fancybox-prev").trigger("click");
}
base._initSwipeGallery();
});
}, 500);
}
}
$(document).ready(function(){
briskController.init();
});
});
/* Header */
.header {
position: relative;
width: 100%;
color: #fill;
background: #bg;
border-bottom: 1px solid fade(#fill, 5);
box-sizing: border-box;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
z-index: 12;
.hamburger,
.contact,
.desktop-nav,
.sidebar-nav {
display: none;
}
}
body.nav-open {
overflow: hidden;
#media #tablet-up {
overflow: auto;
}
}
body:not(.nav-position-sidebar),
body.nav-position-top,
body.nav-position-top-right {
#media #tablet-up {
.header {
position: relative;
padding: 10px 40px;
border-bottom: none;
.transition(~'padding 280ms ease');
.container {
display: table;
overflow-y: hidden;
width: 100%;
height: 80px;
.transition(~'height 280ms ease');
}
.logo {
display: table-cell;
text-align: left;
vertical-align: middle;
max-height: 80px;
overflow: hidden;
a {
padding: 5px 20px 5px 0;
}
}
.desktop-nav {
display: table-cell;
}
.nav {
li {
display: inline-block;
}
a {
padding: 10px 20px;
}
}
.membership-cart {
display: table-cell;
width: 5%;
text-align: right;
white-space: nowrap;
span {
display: inline-block;
}
}
}
&.collapse {
.header {
padding: 5px 40px;
border-bottom: 1px solid fade(#fill, 5);
.container {
height: 40px;
}
}
}
&.full-width-nav-off .header .container {
max-width: 1200px;
margin: 0 auto;
padding: 0 40px;
box-sizing: border-box;
}
}
}
body.nav-position-top-right {
.desktop-nav {
text-align: right;
}
}
.stuck {
position: fixed !important;
top: 0;
}
body.nav-position-sidebar {
#media #tablet-up {
.header {
position: absolute;
top: 0;
left: 0;
width: 260px;
min-height: 100vh;
padding: 40px;
border-bottom: none;
display: flex;
flex-direction: row;
> .nav-wrap {
width: 100%;
min-height: calc(~'100vh - 80px');
display: flex;
flex-direction: column;
> .container {
flex: 1 0 auto;
}
}
.sidebar-nav {
display: block;
}
.nav {
li {
display: block;
}
a {
display: block;
padding: 10px 0;
}
}
.logo {
margin: 0 auto 30px;
}
.membership-cart > span {
display: block;
}
}
.contact {
display: block;
}
.wsite-phone {
display: block;
font-size: 15px;
color: fade(#fill, 40);
padding: 40px 0 0;
text-align: left;
&:before {
content: '';
display: block;
width: 60%;
padding-bottom: 40px;
border-top: 1px solid fade(#fill, 20);
}
}
.wrapper {
background: #bg;
padding-left: 260px;
box-sizing: border-box;
}
}
}
.logo {
* {
display: block;
}
a {
color: #primary;
&:hover {
opacity: 0.6;
background: transparent;
.transition(opacity 200ms ease);
}
}
#wsite-title {
font-family: #font1;
font-size: 30px;
font-weight: 500;
line-height: 1;
text-transform: uppercase;
letter-spacing: 0.08em;
}
img {
overflow: hidden;
max-width: 300px;
max-height: 70px;
}
.wsite-logo {
overflow: hidden;
max-width: 100%;
max-height: 70px;
}
}
/* Nav */
.nav {
vertical-align: middle;
a {
display: block;
color: #fill;
font-family: #font1;
font-size: 15px;
font-weight: 500;
line-height: 1;
letter-spacing: 0.05em;
text-transform: lowercase;
&:hover {
opacity: 0.6;
background: transparent;
.transition(opacity 200ms ease);
}
}
.active {
color: darken(#primary, 10%) !important;
}
#wsite-nav-cart-a {
padding-right: 0;
}
#wsite-nav-cart-num {
position: relative;
display: inline-block;
background: mix(#primary, #bg, 60%);
color: #fill;
min-width: 25px;
padding: 7px 2px;
text-align: center;
border-radius: 100%;
z-index: 2;
#media #tablet-up {
margin: 0 -6px;
}
}
}
.mobile-nav {
display: none;
}
/* Subnav */
#wsite-menus {
> .wsite-menu-wrap {
margin-top: 10px;
}
> .wsite-menu-wrap > .wsite-menu .wsite-menu {
margin: 0 -1px;
}
.wsite-menu {
position: relative;
background: #bg;
.box-shadow(inset 0px 0px 0px 1px fade(#fill, 3));
li a {
padding: 12px 20px;
background: transparent;
color: #fill;
font-family: #font1;
font-size: 14px;
font-weight: normal;
line-height: normal;
text-transform: lowercase;
letter-spacing: 0.05em;
border: none;
&:hover {
opacity: 0.6;
background: transparent;
.transition(opacity 200ms ease);
}
}
}
.wsite-menu-arrow {
display: none;
}
}
/* Sidebar and Mobile Subnav */
.sidebar-nav,
.mobile-nav {
li {
position: relative;
border-color: fade(#fill, 80);
}
.wsite-menu {
padding-left: 5px;
color: fade(#fill, 50);
border-color: fade(#fill, 50);
a {
color: fade(#fill, 50);
}
}
.wsite-menu-wrap {
display: block !important;
overflow: hidden;
max-height: 0;
.transition(all 600ms ease-in-out);
}
.wsite-menu-wrap li.wsite-nav-current > a.wsite-menu-subitem {
background: rgba(0, 0, 0, 0.95);
border: none;
}
.wsite-menu-wrap .wsite-menu-arrow {
display: none;
}
.dropdown {
display: table;
width: 100%;
&:hover {
.icon-caret {
opacity: 0.6;
background: transparent;
}
}
> .icon-caret,
> .dropdown-link {
display: table-cell !important;
vertical-align: top;
a {
display: inline-block !important;
}
}
.icon-caret {
width: 15px;
cursor: pointer;
.transition(all 200ms ease-in-out);
&:before {
content: '';
position: relative;
display: block;
width: 5px;
height: 5px;
border: solid transparent;
border-width: 0 1px 1px 0;
border-color: inherit;
.transform(~'rotate(45deg)');
}
}
&.open span.icon-caret:before {
top: 5px;
.transform(~'rotate(-135deg)');
}
&.open + .wsite-menu-wrap {
width: 100%;
max-height: 1000px;
}
}
}
.sidebar-nav {
.has-submenu > .dropdown span.icon-caret {
padding: 12px 0 8px 10px;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body class="no-header-page">
<div class="header">
<div class="nav-wrap">
<div class="container">
<a class="hamburger" aria-label="Menu" href="#"><span></span></a>
<div class="logo">{logo}</div>
<div class="nav desktop-nav">{menu}</div>
<div class="nav sidebar-nav"><div class="nav-wrap">{menu}</div></div>
<div class="nav membership-cart">{membership}{minicart}</div>
</div>
<div class="nav contact">{phone:text}</div>
</div>
</div>
<div class="wrapper">
<div class="main-wrap">
{{#sections}}
<div class="container">{content}</div>
{{/sections}}
</div>
<div class="footer-wrap">
<div class="footer">{footer}</div>
</div>
</div>
<div class="nav mobile-nav">
<a class="hamburger" aria-label="Menu" href="#"><span></span></a>
{menu}
</div>
<script type="text/javascript" src="/files/theme/plugins.js"></script>
<script type="text/javascript" src="/files/theme/custom.js"></script>
</body>
</html>
The reason not all elements are showing is because of this:
.sidebar-nav .dropdown.open + .wsite-menu-wrap, .mobile-nav .dropdown.open + .wsite-menu-wrap {
width: 100%;
max-height: 1000px;
}
The element is expanded by changing the max-height from 0px to 1000px. The elements in your menu exceed 1000px and they get cut off.
This is actually a pretty comman problem when using CSS transitions to expand elements. CSS transitions only work on height if height is set to an exact value. You can read more about it here: https://css-tricks.com/using-css-transitions-auto-dimensions/
The max-height trick offers a work-around. But it has its draw-back - if the elements expands beyond the value of max-height it gets cut off.
The simplest solution is to simply increase the value of max-height, until all your elements show. This will work, but it' s not ideal if in the future the element expands even more.
More sophisticated (and arguably better) solutions can be found in the css-tricks web page above.
Still, are you sure it's a good idea do display such an enormous amount of of links in an accordion menu? Wouldn't it be better to rethink the navigation, perhaps have a separate page with all the books?

Create grid in HTML

I'm looking to create a grid like this: Grid
I'm using this:
$(document).ready(function() {
for (var i = 0; i < 366; i++) {
$('#div-padre').append('<div class="dia" id="div'+ i +'" /> ');
}
});
to generate 365 divs, then, with CSS, create the 'grid' style.
.dia {
width: 45px;
height: 45px;
background: white;
outline: 2px solid;
float: left;
}
.div-padre {
width: 800px;
}
I tried to clearfix but the last div goes wrong, I don't care if they are divs, tr or whatever, but in the future i would like to select one square and change color, so div or tr or something, I need you to be able to do that later
This is a border/outline management issue, take a look at this:
$(document).ready(function() {
for (var i = 0; i < 366; i++) {
$('#div-padre').append('<div class="dia" id="div'+ i +'" /> ');
}
});
.dia {
width: 45px;
height: 45px;
background: white;
border: 2px solid;
float: left;
margin-top:-2px;
margin-left:-2px;
}
.div-padre {
width: 800px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div-padre"></div>
Use border: 2px solid; margin: -1px; instead of outline: 2px solid;
$(document).ready(function() {
for (var i = 0; i < 365; i++) {
$('#div-padre')
.append(
$('<div>', {
id: 'div-' + (i+1),
class: 'dia'
}));
}
});
.dia {
width: 45px;
height: 45px;
background: white;
border: 2px solid;
margin: -1px;
float: left;
}
.div-padre {
width: 800px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div-padre"></div>

For loop runs length of array but displays one element array.length times

I'm working on a project for freeCodeCamp and I'm running a for loop through an array of twitch.tv users. I've created a table and for each username in my array, it's supposed to add the new row, fill it with the data, and move onto the next element. The problem is that every time I run the code it seems to be choosing a random index in the array and running the loop through to equal the number of elements in the array. I think it's a display issue because it's connecting to the server for each individual call.
Hopefully someone can help me out.
var twitch = ['ESL_SC2', 'OgamingSC2', 'cretetion', 'freecodecamp', 'storbeck', 'habathcx', 'RobotCaleb', 'noobs2ninjas', 'ESL_LOL', 'wow_2', 'brunofin', 'comster404']
var streams = 'https://wind-bow.gomix.me/twitch-api/streams/';
var channels = 'https://wind-bow.gomix.me/twitch-api/channels/';
var users = 'https://wind-bow.gomix.me/twitch-api/users/';
var getStream = function(data) {
if (data.stream === null) {
$('.status').append('Offline');
} else {
var streamStatus = data.stream.channel.status;
var html = '<td class="stream">' + streamStatus + '</td>';
$('.stream').html(html);
}
}
var getChannels = function(data) {
var game = data.display_name;
var logoHtml = data.logo;
var channelUrl = data.url;
var gameHtml = '' + game + '';
var logoHtml = '<img class="image" src="' + logoHtml + '">';
$('.game').html(gameHtml);
$('.logo').html(logoHtml);
}
$(document).ready(function() {
$('.choice').on('click', function() {
$('.choice').removeClass('selected');
$(this).toggleClass('selected');
});
var table = $('<table id="twitch-table"></table>').appendTo('#content');
for (var i = 0; i < twitch.length; i++) {
var row = $('<tr></tr>').appendTo(table);
$('<td class="logo"></td>').appendTo(row);
$('<td class="game"></td>').appendTo(row);
$('<td class="stream"></td>').appendTo(row);
$.getJSON(streams + twitch[i], getStream, 'jsonp');
$.getJSON(channels + twitch[i], getChannels, 'jsonp');
}
});
body {
padding: 0;
margin: 0;
font-family: 'Oswald', sans-serif;
font-size: 100%;
}
a {
text-decoration: none;
}
#main {
width: 600px;
margin: 2% auto 0;
}
#header {
padding: 0;
margin: 0;
background: #116466;
color: #d1e8e2;
line-height: 100px;
width: 100%;
}
h1 {
margin: 0 0 0 5%;
font-size: 300%;
}
#row {
background: #285277;
width: 100%;
}
ul {
margin: 0;
padding: 0;
list-style: none;
display: flex;
justify-content: space-between;
}
.choice {
position: relative;
text-align: center;
width: 33%;
background: #285277;
padding: 5px 10px;
display: inline-block;
color: #d1e8e2;
font-size: 150%;
}
.choice a {
/*padding: 5px 20px;*/
color: #d1e8e2;
}
#content {
width: 100%;
background: #efefef;
}
/*
.choice a:active {
background: #1E3D59;
}
*/
.selected {
background: #1E3D59;
}
.selected:after {
content: '';
position: absolute;
top: 100%;
right: 45%;
width: 0;
height: 0;
border-top: solid 10px #1E3D59;
border-left: solid 10px transparent;
border-right: solid 10px transparent;
}
table {
width: 600px;
}
tr {
margin: 5px 0;
display: flex;
width: 100%;
justify-content: space-between;
}
td {
border-collapse: collapse;
box-sizing: border-box;
margin: 0;
padding: 0;
display: inline-block;
white-space: nowrap;
overflow: hidden;
}
.game {
padding-left: 10px;
width: 100px;
font-size: 120%;
line-height: 75px;
text-overflow: ellipsis;
}
.game a {
color: #111;
}
.image {
height: 75px;
width: 75px;
}
.logo {
padding: 3px 5px;
box-sizing: border-box;
}
.stream {
padding-right: 10px;
width: 350px;
display: inline-block;
text-overflow: ellipsis;
line-height: 75px;
}
<!DOCTYPE html>
<html>
<head>
<title>Twitch.tv JSON API</title>
<link href="https://fonts.googleapis.com/css?family=Oswald" rel="stylesheet">
<script src="https://use.fontawesome.com/57c9bf8971.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<div id='main'>
<header id='header'>
<h1>Twitch Streamers</h1>
</header>
<div id='row'>
<ul>
<li class='choice selected'><a href='#'>All</a></li>
<li class='choice'><a href='#'>Online</a></li>
<li class='choice'><a href='#'>Offline</a></li>
</ul>
</div>
<div id='content'>
</div>
</div>
</body>
</html>
The problem is in these lines:
$('.game').html(gameHtml);
$('.logo').html(logoHtml);
$('.stream').html(html);
They select all lines with game class (or logo or stream) And change them all.
See here a fixed JSfiddle.
You need to use the callback function properly. Your getStreams and getChannels functions are applying data to all rows, instead of its own individual row.
Below are the modified callback functions declarations:
var getStream = function(url, idx) {
$.getJSON(url, function(data){
if (data.stream === null) {
$('.status').append('Offline');
} else {
var streamStatus = data.stream.channel.status;
var html = '<td class="stream">' + streamStatus + '</td>';
$('tr').eq(idx).find('.stream').html(html);
}
});
}
var getChannels = function(url, idx) {
$.getJSON(url, function(data){
var game = data.display_name;
var logoHtml = data.logo;
var channelUrl = data.url;
var gameHtml = '' + game + '';
var logoHtml = '<img class="image" src="' + logoHtml + '">';
$('tr').eq(idx).find('.game').html(gameHtml);
$('tr').eq(idx).find('.logo').html(logoHtml);
});
}
And, call them within your for loop as:
getStream(streams + twitch[i], i);
getChannels(channels + twitch[i], i);
JSFiddle for your reference: https://jsfiddle.net/yogesh214/yxLu9mwg/4/
I understand your problem now:
As #Shalom Peles said, you're using $('.stream') to select all the elements in the document with the class .stream instead of just the element within your row.
Instead use .find to select within an element. For example:
let row = $('<div class="my-row"></div>'); // creates a row
row.append(/* ... */);
let elementInsideRow = row.find('.my-column'); // this selects an element *inside* the row element.
Also: use let instead of var for all declarations
I edited your code to work for streams. Do the same for channels. Read the comments.
var twitch = ['ESL_SC2', 'OgamingSC2', 'cretetion', 'freecodecamp', 'storbeck', 'habathcx', 'RobotCaleb', 'noobs2ninjas', 'ESL_LOL', 'wow_2', 'brunofin', 'comster404']
var streams = 'https://wind-bow.gomix.me/twitch-api/streams/';
var channels = 'https://wind-bow.gomix.me/twitch-api/channels/';
var users = 'https://wind-bow.gomix.me/twitch-api/users/';
// refactor this like I did below
var getChannels = function(data) {
var game = data.display_name;
var logoHtml = data.logo;
var channelUrl = data.url;
var gameHtml = '' + game + '';
var logoHtml = '<img class="image" src="' + logoHtml + '">';
$('.game').html(gameHtml);
$('.logo').html(logoHtml);
}
$(document).ready(function() {
$('.choice').on('click', function() {
$('.choice').removeClass('selected');
$(this).toggleClass('selected');
});
var table = $('<table id="twitch-table"></table>').appendTo('#content');
// you need to use `let` here because you need block scope
// in general, use `let` instead of `var` everywhere.
// https://stackoverflow.com/questions/21906133/when-should-i-use-let-and-var
for (let i = 0; i < twitch.length; i++) {
let row = $('<tr></tr>');
$.getJSON(streams + twitch[i], function(data) {
$('<td class="logo"></td>').appendTo(row);
$('<td class="game"></td>').appendTo(row);
$('<td class="stream"></td>').appendTo(row);
if (data.stream === null) {
// instead of selecting all the elements with `.status`, use `find` to select *within* the `row` element
// $('.status').append('Offline');
row.find('.status').append('Offline');
} else {
var streamStatus = data.stream.channel.status;
var html = '<td class="stream">' + streamStatus + '</td>';
row.find('.stream').html(html);
}
// apend it when you're done
row.appendTo(table);
}, 'jsonp');
// make the same changes for channel
//$.getJSON(channels + twitch[i], getChannels, 'jsonp');
}
});
body {
padding: 0;
margin: 0;
font-family: 'Oswald', sans-serif;
font-size: 100%;
}
a {
text-decoration: none;
}
#main {
width: 600px;
margin: 2% auto 0;
}
#header {
padding: 0;
margin: 0;
background: #116466;
color: #d1e8e2;
line-height: 100px;
width: 100%;
}
h1 {
margin: 0 0 0 5%;
font-size: 300%;
}
#row {
background: #285277;
width: 100%;
}
ul {
margin: 0;
padding: 0;
list-style: none;
display: flex;
justify-content: space-between;
}
.choice {
position: relative;
text-align: center;
width: 33%;
background: #285277;
padding: 5px 10px;
display: inline-block;
color: #d1e8e2;
font-size: 150%;
}
.choice a {
/*padding: 5px 20px;*/
color: #d1e8e2;
}
#content {
width: 100%;
background: #efefef;
}
/*
.choice a:active {
background: #1E3D59;
}
*/
.selected {
background: #1E3D59;
}
.selected:after {
content: '';
position: absolute;
top: 100%;
right: 45%;
width: 0;
height: 0;
border-top: solid 10px #1E3D59;
border-left: solid 10px transparent;
border-right: solid 10px transparent;
}
table {
width: 600px;
}
tr {
margin: 5px 0;
display: flex;
width: 100%;
justify-content: space-between;
}
td {
border-collapse: collapse;
box-sizing: border-box;
margin: 0;
padding: 0;
display: inline-block;
white-space: nowrap;
overflow: hidden;
}
.game {
padding-left: 10px;
width: 100px;
font-size: 120%;
line-height: 75px;
text-overflow: ellipsis;
}
.game a {
color: #111;
}
.image {
height: 75px;
width: 75px;
}
.logo {
padding: 3px 5px;
box-sizing: border-box;
}
.stream {
padding-right: 10px;
width: 350px;
display: inline-block;
text-overflow: ellipsis;
line-height: 75px;
}
<!DOCTYPE html>
<html>
<head>
<title>Twitch.tv JSON API</title>
<link href="https://fonts.googleapis.com/css?family=Oswald" rel="stylesheet">
<script src="https://use.fontawesome.com/57c9bf8971.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<div id='main'>
<header id='header'>
<h1>Twitch Streamers</h1>
</header>
<div id='row'>
<ul>
<li class='choice selected'><a href='#'>All</a></li>
<li class='choice'><a href='#'>Online</a></li>
<li class='choice'><a href='#'>Offline</a></li>
</ul>
</div>
<div id='content'>
</div>
</div>
</body>
</html>

jQuery appending 300 divs in for loop has extra top and bottom margin

Not really sure why there's extra space above and below my boxes that I'm appending in a simple for loop.
HTML:
<body>
<div id="header">
Snake
</div>
<div id="game-container"></div>
</body>
CSS: (I tried a lot of go-tos)
* {
box-sizing: border-box;
margin: 0;
padding: 0;
border: 0;
}
html, body {
border: 0;
padding: 0;
margin: 0;
}
#header {
text-align: center;
font-size: 5em;
color: rgb(0, 50, 105);
}
#game-container {
width: 280px;
padding: 0;
margin: 0 auto;
}
.one-square {
width: 14px;
height: 14px;
border: 1px solid grey;
display: inline-block;
margin: 0;
padding: 0;
}
JQUERY:
$(document).ready(function(){
var div = '<div class="one-square"></div>';
for(var i = 0; i < 300; i++){
$('#game-container').append(div);
}
});
Clearly I'm missing something obvious. Quick codepen to demonstrate: http://codepen.io/anon/pen/WrperX
Just add line-height:0px; to your #game-conatiner div.
#game-container {
width: 280px;
padding: 0;
margin: 0 auto;
line-height:0px; /* ADDED */
}
Working Fiddle
Explanation: While your div has some line-height by default which has height more than your one-square div's so it has space above and below. Adding line-height:0px it will remove it.
Change
.one-square {
display: inline-block;
}
To:
.one-square {
display: block;
float: left;
}
See this updated code-pen
Add line-height: 0em; for the #game-container.
#game-container {
width: 280px;
padding: 0px;
margin: 0px auto;
line-height: 0em;
}
Hope this will solve your problem.

Categories

Resources