I want to display my list of person with a json data structure like this
<pre>
<ul class="list-group">
<span class="badge badge-primary badge-pill">A</span>
<li class="list-group-item d-flex justify-content-between align-items-center">
Jhon PAPOU
</li>
<span class="badge badge-primary badge-pill">B</span>
<li class="list-group-item d-flex justify-content-between align-items-center">
Lionel Melin
</li>
<span class="badge badge-primary badge-pill">C</span>
<li class="list-group-item d-flex justify-content-between align-items-center">
OSMEL GIBI
</li>
</ul>
var jsonData = '[
{"class":"A","name":"Jhon PAPOU","color":"rouge"},
{"class":"B","name":"Lionel Melin","color":"vert"},
{"class":"C","name":"Osmel GIBI","color":"jaune"},
{"class":"D","name":"James DADIN","color":"noir"},
]';
I want to display my list with four small colored tiles at the bottom.
firstview
I cannot reach my desired net display. Any ideas ?
You can use map function for your jsonData to manupulate into HTML UI. So without write css code to manage UI with help of Bootstrap4 Classes.
I hope below snippet will help you lot.
$(document).ready(function(){
var jsonData = [
{"class":"A","name":"Jhon PAPOU","color":"red"},
{"class":"B","name":"Lionel Melin","color":"green"},
{"class":"C","name":"Osmel GIBI","color":"blue"},
{"class":"D","name":"James DADIN","color":"orange"},
];
$('.list-group').after($('<div class="d-flex text-capitalize color-lebel"/>'));
jsonData.map(function(k,v){
$('.list-group').append('<li class="list-group-item d-flex justify-content-start1 align-items-center">'+
'<span class="badge badge-primary badge-pill">'+k.class+'</span>'+
'<span class="m-auto">'+k.name+'</span>'+
'<span class="h-100 d-block position-absolute" style="background:'+k.color+'; width:5px; right:0; top:0;"></span>'+
'</li>');
$('.color-lebel').append('<div class="d-inline-block mr-2 my-2"><span class="badge" style="background:'+k.color+'"> </span> '+k.color+'</div>');
});
});
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container my-3">
<div class="row">
<div class="col-sm-12">
<ul class="list-group"></ul>
</div>
</div>
</div>
Loop the jsonData and use its values in it. you could use forEach or for or for-of
If there is some other issue then please specify it
Can you try the below code to create html
<body id="banner">
<ul id="mylists">
</ul>
</div>
<style>
.list-group-item {
padding: 8px;
list-style: none;
border: solid 1px #eee;
width: 300px;
border-right-width: 5px;
}
.badge {
padding: 3px 10px;
background: #eee;
}
.rouge {
border-right-color: red;
}
.vert {
border-right-color: yellow;
}
.jaune {
border-right-color: green;
}
.noir {
border-right-color: blue;
}
span.name-span {margin-left: 10px;}
</style>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript">
var jsonData = [
{"class":"A","name":"Jhon PAPOU","color":"rouge"},
{"class":"B","name":"Lionel Melin","color":"vert"},
{"class":"C","name":"Osmel GIBI","color":"jaune"},
{"class":"D","name":"James DADIN","color":"noir"}
];
jQuery(document).ready(function($){
$.each(jsonData, function(key,value) {
var html = '';
html+='<li class="list-group-item d-flex justify-content-between align-items-center '+value.color+'" style="border-right-color:'+value.color+';">';
html+='<span class="badge badge-primary badge-pill">'+value.class+'</span>';
html+='<span class="name-span">'+value.name+'</span>';
html+='</li>';
$("#mylists").append(html);
});
});
</script>
.name-span {
margin-left: 10px;
}
.list-group-item {
position: relative;
}
.color-span {
position: absolute;
right: 5px;
top: 60%;
transform: tranlateX(-50%);
width: 20px;
height: 10px;
border-radius: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div id="banner">
<ul id="mylists">
</ul>
</div>
<script type="text/javascript">
var jsonData = [{
"class": "A",
"name": "Jhon PAPOU",
"color": "red"
},
{
"class": "B",
"name": "Lionel Melin",
"color": "blue"
},
{
"class": "C",
"name": "Osmel GIBI",
"color": "green"
},
{
"class": "D",
"name": "James DADIN",
"color": "yellow"
}
];
jQuery(document).ready(function($) {
$.each(jsonData, function(key, value) {
var html = '';
html += '<li class="list-group-item d-flex align-items-center">';
html += '<span class="badge badge-primary badge-pill">' + value.class + '</span>';
html += '<span class="name-span">' + value.name + '</span>'
html += '<span class="color-span" style="background-color:' + value.color + '"></span>';
html += '</li>';
$("#mylists").append(html);
});
});
</script>
You can try below code snippet (please ignore styling as original classes are not known).
Here you can iterate over json data and create required html and while iterating save color codes in an array and later use it for legends.
make sure that you move span inside li instead of outside it
$(function(){
var jsonData = [
{"class":"A","name":"Jhon PAPOU","color":"red"},
{"class":"B","name":"Lionel Melin","color":"green"},
{"class":"C","name":"Osmel GIBI","color":"blue"},
{"class":"D","name":"James DADIN","color":"orange"},
];
var colors = [];
var $ul = $('#list-group');
$.each(jsonData, function(key, value){
var html = '<li class="list-group-item d-flex justify-content-between align-items-center"><span class="badge badge-primary badge-pill">' + value.class + '</span>' + value.name + '<span style="background-color:' + value.color + ';"> </span></li>';
$ul.append(html);
if(colors.indexOf(value.color)==-1) {
colors.push(value.color);
}
});
var colorHTML = '';
$.each(colors, function(index, value){
//console.log(value);
colorHTML += '<span style="background-color:' + value + ';"> </span> <span>' + value +'</span> ';
});
//console.log(colorHTML);
$ul.after(colorHTML);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<ul class="list-group" id="list-group"></ul>
Related
In my project I'm using this drag and drop library called gridstack. You can see their documentation on github here. When you hardcode elements inside the dom and initialize the gridstack, those elements are draggable. But when the elements are created dynamically with a forloop, they are not draggable even if they have the proper draggable classes. How can I make this work?
//initialize grid stack
var grid = GridStack.init({
minRow: 5, // don't collapse when empty
cellHeight: 70,
acceptWidgets: true,// acceptWidgets - accept widgets dragged from other grids or from outside (default: false).
dragIn: '.newWidget', // class that can be dragged from outside
dragInOptions: { revert: 'invalid', scroll: false, appendTo: 'body', helper:'clone' }, // clone or can be your function
removable: '#trash', // drag-out delete class
});
//gridstack on change
grid.on('added removed change', function(e, items) {
let str = '';
items.forEach(function(item) { str += ' (x,y)=' + item.x + ',' + item.y; });
console.log(e.type + ' ' + items.length + ' items:' + str );
});
//dynamic elemenets
const arr = ["Bruh cant drag me!", "Nope me neither", "Me too mouhahaha"];
//loop
for (let i = 0; i < arr.length; i++) {
var div = document.createElement('div');
var el = "<div class='newWidget grid-stack-item ui-draggable ui-resizable ui-resizable-autohide'> <div class='grid-stack-item-content' style='padding: 5px;'> "+arr[i]+"</div></div>";
div.innerHTML = el;
$('.dynamic').append(div);
}
.grid-stack-item-removing {
opacity: 0.8;
filter: blur(5px);
}
#trash {
background: rgba(255, 0, 0, 0.4);
padding: 5px;
text-align: center;
}
.grid-stack-item{
background: whitesmoke;
width: 50%;
border: 1px dashed grey;
}
.grid-stack {
background : #F0FFC0;
}
<!-- jquery -->
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<!-- gridstack-->
<link rel="stylesheet" href="https://gridstackjs.com/node_modules/gridstack/dist/gridstack-extra.min.css"/>
<script src="https://gridstackjs.com/node_modules/gridstack/dist/gridstack-h5.js"></script>
<!-- body-->
<body>
<div id="trash"><span>drop here to remove</span> </div>
<br>
<div class="dynamic"></div>
<div class="newWidget grid-stack-item ui-draggable ui-resizable ui-resizable-autohide">
<div class="grid-stack-item-content" style="padding: 5px;">
<div>
</div>
<div>
<span>I'm original domster! Drag and drop me!</span>
</div>
</div>
</div>
<br>
<div class="grid-stack"></div>
</body>
This issue was raised here. The grid does not automatically track external changes so the grid needs to be re-initialize for the dragIn option to notice the new dynamic widgets
GridStack.setupDragIn()
Full code
//initialize grid stack
var grid = GridStack.init({
minRow: 5, // don't collapse when empty
cellHeight: 70,
acceptWidgets: true,// acceptWidgets - accept widgets dragged from other grids or from outside (default: false).
dragIn: '.newWidget', // class that can be dragged from outside
dragInOptions: { revert: 'invalid', scroll: false, appendTo: 'body', helper:'clone' }, // clone or can be your function
removable: '#trash', // drag-out delete class
});
//gridstack on change
grid.on('added removed change', function(e, items) {
let str = '';
items.forEach(function(item) { str += ' (x,y)=' + item.x + ',' + item.y; });
console.log(e.type + ' ' + items.length + ' items:' + str );
});
//dynamic elemenets
const arr = ["Bruh cant drag me!", "Nope me neither", "Me too mouhahaha"];
//loop
for (let i = 0; i < arr.length; i++) {
var div = document.createElement('div');
var el = "<div class='newWidget grid-stack-item ui-draggable ui-resizable ui-resizable-autohide'> <div class='grid-stack-item-content' style='padding: 5px;'> "+arr[i]+"</div></div>";
div.innerHTML = el;
$('.dynamic').append(div);
}
GridStack.setupDragIn(
'.newWidget',
);
.grid-stack-item-removing {
opacity: 0.8;
filter: blur(5px);
}
#trash {
background: rgba(255, 0, 0, 0.4);
padding: 5px;
text-align: center;
}
.grid-stack-item{
background: whitesmoke;
width: 50%;
border: 1px dashed grey;
}
.grid-stack {
background : #F0FFC0;
}
<!-- jquery -->
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<!-- gridstack-->
<link rel="stylesheet" href="https://gridstackjs.com/node_modules/gridstack/dist/gridstack-extra.min.css"/>
<script src="https://gridstackjs.com/node_modules/gridstack/dist/gridstack-h5.js"></script>
<!-- body-->
<body>
<div id="trash"><span>drop here to remove</span> </div>
<br>
<div class="dynamic"></div>
<div class="newWidget grid-stack-item ui-draggable ui-resizable ui-resizable-autohide">
<div class="grid-stack-item-content" style="padding: 5px;">
<div>
</div>
<div>
<span>I'm original domster! Drag and drop me!</span>
</div>
</div>
</div>
<br>
<div class="grid-stack"></div>
</body>
I have a simple bit of JS used to show / hide DIVs:
function HideShow(e, itm_id) {
var tbl = document.getElementById(itm_id);
if (tbl.style.display == ""){
e.innerHTML = "<i class='fa fa-plus' aria-hidden='true'></i>";
tbl.style.display = "none"; }
else {
e.innerHTML = "<i class='fa fa-minus' aria-hidden='true'></i>";
tbl.style.display = ""; }
}
This is a working example of the code on Codepen: Show Hide Divs without jQuery
This is an example of one section:
<div id="activities" style="margin-bottom:50px;">
<div style="color: #000; background: #eee; border-bottom:1px solid #ccc; padding:5px;">
<h1 class="heading"><i class='fa fa-minus' aria-hidden='true'></i> Activities <span style="color:#ccc;"></span></h1>
</div>
<div id="parent_activities" style="background: #fff; padding:20px;">
<div id="activities__award-medal" style="background: #fff; padding-left:10px; background:#f1f1f1; border-top:1px solid #fff; font-size:30px;"><i class='fa fa-minus' aria-hidden='true'></i> award-medal <span style="color:#ccc;"></span></div>
<div id="child_award-medal" style="background: #fff; padding:20px;">
<ul class="gallery grid">
<li>
<a href="#">
<img title="military medal - 🎖️" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f396.svg" style="width:64x; height:64px" role="presentation">
</a>
</li>
</ul>
</div>
<div id="activities__event" style="background: #fff; padding-left:10px; background:#f1f1f1; border-top:1px solid #fff; font-size:30px;"><i class='fa fa-minus' aria-hidden='true'></i> event <span style="color:#ccc;"></span></div>
<div id="child_event" style="background: #fff; padding:20px;">
<ul class="gallery grid">
<li>
<a href="#">
<img title="jack-o-lantern - 🎃" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f383.svg" style="width:64x; height:64px" role="presentation">
</a>
</li>
</ul>
</div>
</div>
</div>
The top level example has an id of parent_activities and then there are two child values:
child_award-medal
child_event
I'd like to work out how to add two links:
A link to toggle the HideShow function for the parents so that all divs with an ID starting with parent_ are shown / hidden
A link to toggle the HideShow function for the children so that all divs with an ID starting with child_ are shown / hidden
I'm not sure how I'd go about that though.
Any advice much appreciated. Thanks
Note: this isn't a fully complete solution. The intention is to assist you in the parts that are giving you pause.
Try not to embed JavaScript in your HTML body; it's unnecessary markup and makes it difficult to track down and debug errors. I did not change your existing calls, but demonstrate how it can be done by using addEventListener with the newer code
You can target your elements using document.querySelectorAll and looking for the prefix you're interested in (e.g., parent_, child_). Which prefixes to use have been added to the links in the data-selector attributes
because the toggling action is not going to another page, these should be buttons or spans
to hide elements, you can use the Bootstrap display classes, as I have used d-none which stands for display none. The Bootstrap library provides these to make it especially easier for responsive layouts
many of your inline-CSS should be in classes, this is to both reduce your markup and make it more organized
// So forEach can be used on 'querySelectorAll' and 'getElementsByClassName' collections
HTMLCollection.prototype.forEach = NodeList.prototype.forEach = Array.prototype.forEach;
function HideShow(e, itm_id) {
var tbl = document.getElementById(itm_id);
if (tbl.style.display == "") {
e.innerHTML = "<i class='fa fa-plus' aria-hidden='true'></i>";
tbl.style.display = "none";
} else {
e.innerHTML = "<i class='fa fa-minus' aria-hidden='true'></i>";
tbl.style.display = "";
}
}
// -----------------------------------------------------------
// NEW Code
// New toggle links
let toggles = document.getElementsByClassName('toggler');
// Attach click event
toggles.forEach(link => link.addEventListener('click', fnToggleElement))
// Event handler definition
function fnToggleElement() {
let elements = document.querySelectorAll(`[id^="${this.dataset.selector}"]`)
let className = 'd-none'
elements.forEach(el => {
let fas = el.parentElement.closest('.item,.sub-container,.menu-container').querySelectorAll('.fa')
if (el.classList.contains(className)) {
el.classList.remove(className)
fas.forEach(fa => {
fa.classList.remove('fa-plus')
fa.classList.add('fa-minus')
})
} else {
el.classList.add(className)
fas.forEach(fa => {
fa.classList.remove('fa-minus')
fa.classList.add('fa-plus')
})
}
})
}
.menu-container {
margin-bottom: 50px;
}
.sub-container {
padding: 20px;
}
.heading {
color: #000;
background: #eee;
border-bottom: 1px solid #ccc;
padding: 5px;
}
.indent {
background: #fff;
padding: 20px;
}
.icon {
width: 64px;
height: 64px;
}
.item {
background: #fff;
padding-left: 10px;
background: #f1f1f1;
border-top: 1px solid #fff;
font-size: 30px;
}
.toggler {
cursor: pointer;
display: inline-block;
}
.gallery {
width: 100%;
*width: 99.94877049180327%;
margin: 0;
padding: 0;
}
.gallery.grid li {
margin: 2px 5px;
}
.gallery.grid li {
margin: 2px 5px;
display: block;
}
.gallery.grid li:hover {
background: #ccc;
}
.gallery.grid li {
display: inline-block;
border-top: 1px solid #eee;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-left: 1px solid #eee;
padding: 6px;
position: relative;
-moz-box-sizing: border-box;
border-radius: 3px 3px 3px 3px;
background: #fff;
}
.gallery a {
display: block;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
<div class="container-fluid">
<div class="row">
<div class="col-sm"><span class="toggler btn-link" data-selector="parent_">Toggle Parents</span></div>
<div class="col-sm"><span class="toggler btn-link" data-selector="child_">Toggle Children</span></div>
</div>
</div>
<div class="container-fluid">
<div id="activities" class="menu-container">
<h1 class="heading">
<a href="javascript:;" onclick="HideShow(this,'parent_activities')">
<i class='fa fa-minus' aria-hidden='true'></i>
</a> Activities
<span style="color:#ccc;"></span>
</h1>
<div id="parent_activities" class="sub-container">
<div id="activities__award-medal" class="item">
<a href="javascript:;" onclick="HideShow(this,'child_award-medal')">
<i class='fa fa-minus' aria-hidden='true'></i>
</a> award-medal
<span style="color:#ccc;"></span>
</div>
<div id="child_award-medal" class="indent">
<ul class="gallery grid">
<li>
<a href="# ">
<img title="military medal - 🎖️" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f396.svg " class="icon" role="presentation">
</a>
</li>
</ul>
</div>
<div id="activities__event " class="item">
<a href="javascript:; " onclick="HideShow(this, 'child_event') ">
<i class='fa fa-minus' aria-hidden='true'></i>
</a> event
<span style="color:#ccc; "></span>
</div>
<div id="child_event " class="indent">
<ul class="gallery grid ">
<li>
<a href="# ">
<img title="jack-o-lantern - 🎃" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f383.svg" class="icon" role="presentation">
</a>
</li>
</ul>
</div>
</div>
</div>
<div id="animals-nature" class="menu-container">
<h1 class="heading"><i class='fa fa-minus' aria-hidden='true'></i> Animals & Nature <span style="color:#ccc;"></span></h1>
<div id="parent_animals-nature" class="sub-container">
<div id="animals-nature__animal-amphibian " class="item ">
<a href="javascript:;" onclick="HideShow(this, 'child_animal-amphibian')">
<i class='fa fa-minus' aria-hidden='true'></i>
</a> animal-amphibian
<span style="color:#ccc;"></span>
</div>
<div id="child_animal-amphibian" class="indent">
<ul class="gallery grid">
<li>
<a href="# ">
<img title="frog face - 🐸 " src="https://cdn.jsdelivr.net/emojione/assets/svg/1f438.svg " style="width:64x; height:64px " role="presentation ">
</a>
</li>
</ul>
</div>
<div id="animals-nature__animal-bird " class="item">
<a href="javascript:;" onclick="HideShow(this, 'child_animal-bird')">
<i class='fa fa-minus' aria-hidden='true'></i>
</a> animal-bird
<span style="color:#ccc;"></span>
</div>
<div id="child_animal-bird" class="indent">
<ul class="gallery grid">
<li>
<a href="# ">
<img title="turkey - 🦃 " src="https://cdn.jsdelivr.net/emojione/assets/svg/1f983.svg " style="width:64x; height:64px " role="presentation ">
</a>
</li>
</ul>
</div>
</div>
</div>
Try the following selector and apply:
document.querySelectorAll('[id^="child_"]')
See the below snippet for an example:
function toggleIdStartingWith( prefix = 'parent_' ){
// Select all IDs starting with prefix and turn this NodeList into an array
// so we can loop through it easily later.
var all = [...document.querySelectorAll(`[id^="${prefix}"]`)];
// Determine whether we want to turn them on or off by
// checking the first element. You might want to also check
// if any elements are found at all before doing this.
var hidden = all[ 0 ].style.display === 'none';
// Apply the display style to all.
all.forEach(element => {
element.style.display = hidden ? '' : 'none';
});
// Return the inverted hidden value, which is what we applied.
// Useful if you want to toggle stuff, and then see what the result
// was in the code that called the function.
return !hidden;
}
// For testing purposes I am hooking two buttons up for testing this.
document.getElementById('hideshow_parents').addEventListener( 'click', event => {
event.preventDefault()
event.target.textContent = toggleIdStartingWith( 'parent_' )
? 'Show all Parents'
: 'Hide all Parents'
})
document.getElementById('hideshow_children').addEventListener( 'click', event => {
event.preventDefault()
event.target.textContent = toggleIdStartingWith( 'child_' )
? 'Show all Children'
: 'Hide all Children'
})
<div id="parent_1">Parent</div>
<div id="child_1">Child</div>
<div id="parent_2">Parent</div>
<div id="child_2">Child</div>
<div id="parent_3">Parent</div>
<div id="child_3">Child</div>
<div id="parent_4">Parent</div>
<div id="child_4">Child</div>
<div id="parent_5">Parent</div>
<div id="child_5">Child</div>
<button id="hideshow_parents">Hide/Show Parents</button>
<button id="hideshow_children">Hide/Show Children</button>
As you asked in the comment, switching the classes depending on the toggle state is easy too. I personally think you shouldn't mix html and interactivity, so I am going to use addEventListener in my example:
function toggleIdStartingWith( prefix = 'parent_' ){
var all = [...document.querySelectorAll(`[id^="${prefix}"]`)];
var hidden = all[ 0 ].style.display === 'none';
all.forEach(element => {
element.style.display = hidden ? '' : 'none';
});
return !hidden;
}
document.querySelector('h1').addEventListener( 'click', event => {
event.preventDefault()
if( toggleIdStartingWith( 'parent_' ) ){
event.target.textContent = 'Show';
event.target.classList.remove( 'fa-minus' )
event.target.classList.add( 'fa-plus' )
} else {
event.target.textContent = 'Hide';
event.target.classList.add( 'fa-minus' )
event.target.classList.remove( 'fa-plus' )
}
})
.fa-minus:before { content: '-'; }
.fa-plus:before { content: '+'; }
<div id="parent_1">Parent</div>
<div id="parent_2">Parent</div>
<div id="parent_3">Parent</div>
<div id="parent_4">Parent</div>
<div id="parent_5">Parent</div>
<h1 class="fa-minus">Hide</h1>
If you are insistent on getting it as an onclick in your html, just wrap it in a function:
function toggle( target, prefix ){
if( toggleIdStartingWith( prefix ) ){
target.textContent = 'Show';
target.classList.remove( 'fa-minus' )
target.classList.add( 'fa-plus' )
} else {
target.textContent = 'Hide';
target.classList.add( 'fa-minus' )
target.classList.remove( 'fa-plus' )
}
}
And call it as such:
<h1 onclick="toggle( this, 'parent_); return false;'"></h1>
Also, just so you know, it might be good to return false if you are going to use onclick handlers in HTML to prevent the default events from occuring. Then you can just leave your link set to # instead of the ugly javascript:;.
You should use querySelectorAll() to select "IDs starting with...". This can be done like document.querySelectorAll('[id^="start_"]') and then you iterate through the elements applying the style to hide or show.
Check out this fiddle: https://jsfiddle.net/1c38dezk/
You should use querySelectorAll() to select "IDs starting with...".
Have a nice day
Report designer detail band contains Add band button which shoud add new panels immediately before and after detail panel.
$parentpanel = $this.parents(".designer-panel:first");
is used to find parent panel and .prepend() / append() to add new panels.
Panels are added as Detail panel child elements.
How to add panels before and after Detail panel in same DOM level like group header and footer panels in sample html.
Elements should probably added to $parentpanel.parent() element list before and after $parentpanel element.
Is there some selector or append command in jQuery for this ?
$(function() {
var startpos,
selected = $([]),
offset = {
top: 0,
left: 0
};
$('#designer-detail-addband').on('click', function() {
var $this = $(this),
$parentpanel = $this.parents(".designer-panel:first");
$parentpanel.prepend('<div class="panel designer-panel">' +
'<div class="panel-body designer-panel-body" style="height:1px">' +
'</div>' +
'<div class="bg-warning">' +
'<div class="panel-footer"><i class="glyphicon glyphicon-chevron-up">' +
'</i> Group heade {0}: <span id="band{0}_expr" contenteditable="true">"groupexpression"</span>' +
'</div></div></div>');
$parentpanel.append('<div class="panel designer-panel">' +
'<div class="panel-body designer-panel-body" style="height:1px"></div>' +
'<div class="bg-warning">' +
'<div class="panel-footer"><i class="glyphicon glyphicon-chevron-up">' +
'</i> Group footer {0}' +
'</div></div></div>');
});
$(".designer-panel-body").droppable({
accept: ".designer-field"
});
$(".designer-field").draggable({
start: function(event, ui) {
var $this = $(this);
if ($this.hasClass("ui-selected")) {
selected = $(".ui-selected").each(function() {
var el = $(this);
el.data("offset", el.offset());
});
} else {
selected = $([]);
$(".designer-field").removeClass("ui-selected");
}
offset = $this.offset();
},
drag: function(event, ui) {
// drag all selected elements simultaneously
var dt = ui.position.top - offset.top,
dl = ui.position.left - offset.left;
selected.not(this).each(function() {
var $this = $(this);
var elOffset = $this.data("offset");
$this.css({
top: elOffset.top + dt,
left: elOffset.left + dl
});
});
}
});
$(".panel-resizable").resizable({
minWidth: "100%",
maxWidth: "100%",
minHeight: 1
});
})
.panel-resizable {
min-height: 1px;
overflow: hidden;
margin: 0;
padding: 0;
}
.designer-field {
border: 1px solid lightgray;
white-space: pre;
overflow: hidden;
position: absolute;
}
.designer-panel-body {
min-height: 1px;
overflow: hidden;
margin: 0;
padding: 0;
}
.panel-footer {
padding: 0;
}
.designer-panel,
.panel-body {
margin: 0;
padding: 0;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
</head>
<body>
<div class='panel designer-panel'>
<div class='panel-body designer-panel-body panel-resizable' style='height:2cm'>
<div class='designer-field' style='left:5px;top:6px;width:180px'>field 1 in group 1 header</div>
<div class='designer-field' style='left:54px;top :36px;width:160px'>field 2 in group 1 header</div>
</div>
<div class='panel-footer'>Group 1 Header</div>
</div>
<div class='panel designer-panel'>
<div class='panel-body panel-resizable' style='height:1cm'>
<div class='designer-field' style='left:24px;top:2px;width:140px'>field in detail group</div>
</div>
<div class='panel-footer panel-primary'>Detail <a role="button" id="designer-detail-addband"> Add group</a>
</div>
</div>
<div class='panel'>
<div class='panel-body panel-resizable' style='height:1cm'>
<div class='designer-field' style='left:44px;top:2px;width:140px'>field in group 1 footer</div>
</div>
<div class='panel-footer panel-warning'>Group 1 Footer</div>
</div>
Try jQuery's before, after functions. Or insertBefore, insertAfter
Also you can use
$this.closest(".designer-panel");
instead of
$this.parents(".designer-panel:first");
See closest
Report designer layout contains Bootstrap 3 panels.
Detail panel has Add group button which should add new panels before and after it.
This is implemented in onclick event handler using jquery prepend and append:
var $this = $(this),
$parentpanel = $this.parents(".designer-panel").get(0);
$parentpanel.prepend('<div class="panel designer-panel">' +
'<div class="panel-body designer-panel-body" style="height:1px">' +
'</div>' +
'<div class="bg-warning">' +
'<div class="panel-footer"><i class="glyphicon glyphicon-chevron-up">' +
'</i> Group heade {0}: <span id="band{0}_expr" contenteditable="true">"group expression"</span>' +
'</div></div></div>');
$parentpanel.append('<div class="panel designer-panel">' +
'<div class="panel-body designer-panel-body" style="height:1px">' +
'</div>' +
'<div class="bg-warning">' +
'<div class="panel-footer"><i class="glyphicon glyphicon-chevron-up">' +
'</i> Group footer {0}' +
'</div></div></div>');
});
If clicked in Add band button html appears instead of panel.
It looks like jquery preoend and append does not add dom objects work for unknown reason.
How to fix this so that new panels appear before and after detail panel ?
$(function() {
var startpos,
selected = $([]),
offset = { top: 0, left: 0 };
$('#designer-detail-addband').on('click', function () {
var $this = $(this),
$parentpanel = $this.parents(".designer-panel").get(0);
$parentpanel.prepend('<div class="panel designer-panel">' +
'<div class="panel-body designer-panel-body" style="height:1px">' +
'</div>' +
'<div class="bg-warning">' +
'<div class="panel-footer"><i class="glyphicon glyphicon-chevron-up">' +
'</i> Group heade {0}: <span id="band{0}_expr" contenteditable="true">"groupexpression"</span>' +
'</div></div></div>');
$parentpanel.append('<div class="panel designer-panel">' +
'<div class="panel-body designer-panel-body" style="height:1px"></div>' +
'<div class="bg-warning">' +
'<div class="panel-footer"><i class="glyphicon glyphicon-chevron-up">' +
'</i> Group footer {0}' +
'</div></div></div>');
});
$(".designer-panel-body").droppable({
accept: ".designer-field"
});
$(".designer-field").draggable({
start: function (event, ui) {
var $this = $(this);
if ($this.hasClass("ui-selected")) {
selected = $(".ui-selected").each(function () {
var el = $(this);
el.data("offset", el.offset());
});
} else {
selected = $([]);
$(".designer-field").removeClass("ui-selected");
}
offset = $this.offset();
},
drag: function (event, ui) {
// drag all selected elements simultaneously
var dt = ui.position.top - offset.top, dl = ui.position.left - offset.left;
selected.not(this).each(function () {
var $this = $(this);
var elOffset = $this.data("offset");
$this.css({ top: elOffset.top + dt, left: elOffset.left + dl });
});
}
});
$(".panel-resizable").resizable({
minWidth: "100%",
maxWidth: "100%",
minHeight: 1
});
});
.panel-resizable {
min-height: 1px;
overflow: hidden;
margin: 0;
padding: 0;
}
.designer-field {
border: 1px solid lightgray;
white-space: pre;
overflow: hidden;
position: absolute;
}
.designer-panel-body {
min-height: 1px;
overflow: hidden;
margin: 0;
padding: 0;
}
.panel-footer {
padding: 0;
}
.designer-panel, .panel-body {
margin: 0;
padding: 0;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
</head>
<body>
<div class='panel designer-panel'>
<div class='panel-body designer-panel-body panel-resizable' style='height:2cm'>
<div class='designer-field' style='left:5px;top:6px;width:180px'>field 1 in group 1 header</div>
<div class='designer-field' style='left:54px;top :36px;width:160px'>field 2 in group 1 header</div>
</div>
<div class='panel-footer'>Group 1 Header</div>
</div>
<div class='panel designer-panel'>
<div class='panel-body panel-resizable' style='height:1cm'>
<div class='designer-field' style='left:24px;top:2px;width:140px'>field in detail group </div>
</div>
<div class='panel-footer panel-primary'>Detail <a role="button" id="designer-detail-addband"> Add group</a></div>
</div>
<div class='panel'>
<div class='panel-body panel-resizable' style='height:1cm'>
<div class='designer-field' style='left:44px;top:2px;width:140px'>field in group 1 footer</div></div>
<div class='panel-footer panel-warning'>Group 1 Footer</div>
</div>
I think your issue is here:
$parentpanel = $this.parent(".designer-panel");
jQuery parent only goes one level up the DOM, and looking at your HTML the first div with .designer-panel is several levels up from your anchor. If you change it to the code below then you should hopefully get the element you want.
$parentpanel = $this.parents(".designer-panel").get(0);
I was trying to iterate the 'streamers' array by the variable showindex but failed,it just shows the first element "monstercat" and last element "amazhs" of the array, using debug in chrome and showindex in the displayResult function always is 0 and 9, can't figure out why. Any ideas?
var streamers = ['monstercat', 'sivhd', 'cryaotic', 'nightblue3', 'picoca_lol', 'freecodecamp', 'trick2g', 'riotgamesbrazil', 'riotgames', 'amazhs'];
$(document).ready(function() {
var logo = "";
var channelName = "";
var showindex = 0;
streamers.forEach(function(streamer, index) {
showindex = index;
$.ajax({
type: 'GET',
jsonp: "callback",
url: 'https://api.twitch.tv/kraken/streams/' + streamer,
headers: {
'Client-ID': 'd50b88uvtwlhdfrqi3vj3k1hm3izkyx'
},
success: displayResult
});
});
function displayResult(data) {
var outstring = "";
if (data.stream !== null) {
channelName = data.stream.channel.display_name;
logo = data.stream.channel.logo;
} else {
logo = "https://placeholdit.imgix.net/~text?txtsize=6&txt=50%C3%9750&w=50&h=50";
channelName = streamers[showindex];
}
outstring +=
"<li class='streamer'>" +
"<img class='streamer-icon' src='" + logo + "'/>" +
"<p class='streamer-name'>" +
"<a href='http://twitch.tv/" + channelName + "' target='_blank'>" + channelName + "</a></p>" +
"<span class='streamer-status'>" +
"<i class='fa fa-exclamation'></i></span></li>"
$("#showBox").append(outstring);
}
});
ul {
padding: 0;
margin: 0;
}
.tab-content {
border: 1px solid #ddd;
border-top: none;
}
.streamer {
list-style-type: none;
padding: 10px;
}
.streamer-icon {
width: 50px;
}
.streamer-name {
display: inline-block;
margin-left: 10px;
}
.streamer-status {
float: right;
padding-top: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div class="container">
<div class="row col-md-4 col-md-offset-4">
<ul class="nav nav-tabs" role="tablist">
<li class="active">all
</li>
<li>online
</li>
<li>offline
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="all">
<ul id="showBox">
</ul>
</div>
<div class="tab-pane" id="online">
<ul></ul>
</div>
<div class="tab-pane" id="offline">
<ul></ul>
</div>
</div>
</div>
</div>
It's because the calls are all happening at the same time so instantly showindex = 9 a way around this would be to do the incrementation in displayResult though it could still go wrong (but it's less likely).
You probably could change your code entirely to make it use promises which would be a lot safer.
var streamers = ['monstercat', 'sivhd', 'cryaotic', 'nightblue3', 'picoca_lol', 'freecodecamp', 'trick2g', 'riotgamesbrazil', 'riotgames', 'amazhs'];
$(document).ready(function() {
var logo = "";
var channelName = "";
var showindex = 0;
streamers.forEach(function(streamer, index) {
$.ajax({
type: 'GET',
jsonp: "callback",
url: 'https://api.twitch.tv/kraken/streams/' + streamer,
headers: {
'Client-ID': 'd50b88uvtwlhdfrqi3vj3k1hm3izkyx'
},
success: displayResult
});
});
function displayResult(data) {
var outstring = "";
if (data.stream !== null) {
channelName = data.stream.channel.display_name;
logo = data.stream.channel.logo;
} else {
logo = "https://placeholdit.imgix.net/~text?txtsize=6&txt=50%C3%9750&w=50&h=50";
channelName = streamers[showindex];
}
outstring +=
"<li class='streamer'>" +
"<img class='streamer-icon' src='" + logo + "'/>" +
"<p class='streamer-name'>" +
"<a href='http://twitch.tv/" + channelName + "' target='_blank'>" + channelName + "</a></p>" +
"<span class='streamer-status'>" +
"<i class='fa fa-exclamation'></i></span></li>"
$("#showBox").append(outstring);
showindex++;
}
});
ul {
padding: 0;
margin: 0;
}
.tab-content {
border: 1px solid #ddd;
border-top: none;
}
.streamer {
list-style-type: none;
padding: 10px;
}
.streamer-icon {
width: 50px;
}
.streamer-name {
display: inline-block;
margin-left: 10px;
}
.streamer-status {
float: right;
padding-top: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div class="container">
<div class="row col-md-4 col-md-offset-4">
<ul class="nav nav-tabs" role="tablist">
<li class="active">all
</li>
<li>online
</li>
<li>offline
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="all">
<ul id="showBox">
</ul>
</div>
<div class="tab-pane" id="online">
<ul></ul>
</div>
<div class="tab-pane" id="offline">
<ul></ul>
</div>
</div>
</div>
</div>
Here's another way to do it, it doesn't use foreach but iterates through the array another way. This way is a bit slower but means it doesn't get ahead of itself (you can actually see each one pop in)
var streamers = ['monstercat', 'sivhd', 'cryaotic', 'nightblue3', 'picoca_lol', 'freecodecamp', 'trick2g', 'riotgamesbrazil', 'riotgames', 'amazhs'];
$(document).ready(function() {
var logo = "";
var channelName = "";
var showindex = 0;
//Work out if there are any streamers left in the array
function calcStreamers() {
if (showindex < (streamers.length - 1)) {
//if there are add 1 and go get it
showindex++;
streamersGet();
} else {
//if not just stop
return false
}
};
//The get function
function streamersGet() {
$.ajax({
type: 'GET',
jsonp: "callback",
url: 'https://api.twitch.tv/kraken/streams/' + streamers[showindex],
headers: {
'Client-ID': 'd50b88uvtwlhdfrqi3vj3k1hm3izkyx'
},
success: displayResult
});
};
function displayResult(data) {
var outstring = "";
if (data.stream !== null) {
channelName = data.stream.channel.display_name;
logo = data.stream.channel.logo;
} else {
logo = "https://placeholdit.imgix.net/~text?txtsize=6&txt=50%C3%9750&w=50&h=50";
channelName = streamers[showindex];
}
outstring +=
"<li class='streamer'>" +
"<img class='streamer-icon' src='" + logo + "'/>" +
"<p class='streamer-name'>" +
"<a href='http://twitch.tv/" + channelName + "' target='_blank'>" + channelName + "</a></p>" +
"<span class='streamer-status'>" +
"<i class='fa fa-exclamation'></i></span></li>"
$("#showBox").append(outstring);
//Once the data has been added to the page go and check if there are more to add
calcStreamers();
}
//Initally start by getting the first result
streamersGet();
});
ul {
padding: 0;
margin: 0;
}
.tab-content {
border: 1px solid #ddd;
border-top: none;
}
.streamer {
list-style-type: none;
padding: 10px;
}
.streamer-icon {
width: 50px;
}
.streamer-name {
display: inline-block;
margin-left: 10px;
}
.streamer-status {
float: right;
padding-top: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div class="container">
<div class="row col-md-4 col-md-offset-4">
<ul class="nav nav-tabs" role="tablist">
<li class="active">all
</li>
<li>online
</li>
<li>offline
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="all">
<ul id="showBox">
</ul>
</div>
<div class="tab-pane" id="online">
<ul></ul>
</div>
<div class="tab-pane" id="offline">
<ul></ul>
</div>
</div>
</div>
</div>
You wanted to iterate through the array correct?
var streamers = ['monstercat', 'sivhd', 'cryaotic', 'nightblue3', 'picoca_lol', 'freecodecamp', 'trick2g', 'riotgamesbrazil', 'riotgames', 'amazhs'];
$(document).ready(function() {
$(streamers).each(function(index, streamer){
console.log(streamer+" "+index);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>