Issue
I made an HTML page that allows you to click a button to add row and column
division. At the moment, the row div
is added to the container
div. I want to switch from the standard div adding to one that is mouse-click driven. This means that when a user clicks
a button and selects a div
, a row block is appended to that div. Looking for a solution
var i = 0;
var j = 0;
let newColNode = null;
function addRow() {
const row = document.createElement('div');
row.className = 'bloc';
row.id = "b" + ++i;
document.getElementById('contentBox').append(row);
row.addEventListener('click', function(event) {
console.log(newColNode)
console.log(row)
if (newColNode != null)
row.appendChild(newColNode);
newColNode = null
});
}
// Column Addition
function addCol() {
const col = document.createElement('div');
col.className = 'bloc--inner';
col.id = "c" + ++j;
newColNode = col;
}
* {
box-sizing: border-box;
}
.wrapper {
float: left;
width: 100%;
height: 100vh;
}
body {
padding: 0;
margin: 0;
position: relative;
}
.main-content {
float: left;
width: calc(100%);
height: 100%;
background: #fafafa;
}
.header {
height: 60px;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0 20px;
}
.content-box {
width: 100%;
height: calc(100% - 60px);
padding: 15px;
}
button {
background: #000;
border: 0;
padding: 0 20px;
height: 40px;
margin-left: 10px;
font-weight: 600;
color: white;
cursor: pointer;
}
.row-block {
width: 100%;
border: 2px dashed #848484;
padding: 20px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-bottom: 20px;
}
.row-block:hover {
border-color: #2654d1;
}
.column-block {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 10px;
padding-left: 10px;
margin: 0 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
border: 2px dashed #848484;
background-color: #dedede;
padding: 20px;
}
.column-block:first-child {
margin-left: 0;
}
.column-block:last-child {
margin-right: 0;
}
.row-block .each-draggable-item {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 10px;
padding-left: 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
margin-bottom: 0;
}
.gu-mirror {
cursor: grabbing;
}
.container .ex-moved {
background-color: #e74c3c;
}
.container.ex-over {
background-color: rgba(255, 255, 255, 0.3);
}
.handle {
background-color: rgba(0, 0, 0, 0.4);
cursor: move;
margin-right: 5px;
padding: 0 5px;
}
.column-block h5 {
margin: 0;
}
/* .gu-mirror {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
position: fixed !important;
margin: 0 !important;
z-index: 9999 !important;
opacity: 1;
}
.gu-hide {
display: none !important;
}
.gu-unselectable {
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
}
.gu-transit {
opacity: 0.4;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
} */
.gu-transit {
opacity: 0.4;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
transition: .3s ease-out;
}
.container {
width: 100%;
}
.bloc {
width: 100%;
border: 2px dashed #848484;
background: #ffefef;
margin-bottom: 20px;
padding: 20px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
.bloc--inner {
margin: 0 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
border: 2px dashed #848484;
background-color: #d4ecff;
padding: 20px;
}
.bloc--inner:first-child {
margin-left: 0;
}
.bloc--inner:last-child {
margin-right: 0;
}
.bloc--inner .bloc {
margin: 0;
}
<div class="wrapper">
<div class="main-content">
<div class="header">
<button class="add-row" onclick="addRow()">Add Row +</button>
<button class="add-column" onclick="addCol()">Add Column +</button>
</div>
<div class="content-box" id="main-container">
<div class="container" id="contentBox">
</div>
</div>
</div>
</div>
Thanks in advance!!
Currently the div is appedning to the container div
Solution
Is this more or less the intended result? Click on a div
and then click on either button to add the appropriate element to the previously clicked div
?
var i = 0;
var j = 0;
let parent=false;
/* delegated listener to set the global variable used to determine where new elements are added */
document.querySelector('#main-container > .container').addEventListener('click',e=>{
parent=e.target;
});
/* remove elements using right-click */
document.querySelector('#main-container > .container').addEventListener('contextmenu',e=>{
e.preventDefault();
try{
if( parent )parent.removeChild(e.target);
}catch(err){
console.clear();
console.log(err.message);
}
});
const warnuser=(e)=>{
if( !parent ){
return alert('Click a suitable parent to begin');
}
return true;
}
function addRow() {
if( warnuser() ){
i++;
const row = document.createElement('div');
row.className='bloc';
row.id = `b${i}`;
parent.append( row );
return row;}
}
function addCol() {
if( warnuser() ){
j++;
const col=document.createElement('div');
col.className='bloc--inner';
col.id = `c${j}`;
parent.append( col );
return col;
}
}
* {
box-sizing: border-box;
}
/*
to ensure user can see contentBox initially
*/
.container{
border:2px dashed grey;
padding:1rem
}
.bloc:after,
.bloc--inner:after{
content:attr(id)
}
.wrapper {
float: left;
width: 100%;
height: 100vh;
}
body {
padding: 0;
margin: 0;
position: relative;
}
.main-content {
float: left;
width: calc(100%);
height: 100%;
background: #fafafa;
}
.header {
height: 60px;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0 20px;
}
.content-box {
width: 100%;
height: calc(100% - 60px);
padding: 15px;
}
button {
background: #000;
border: 0;
padding: 0 20px;
height: 40px;
margin-left: 10px;
font-weight: 600;
color: white;
cursor: pointer;
}
.row-block {
width: 100%;
border: 2px dashed #848484;
padding: 20px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-bottom: 20px;
}
.row-block:hover {
border-color: #2654d1;
}
.column-block {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 10px;
padding-left: 10px;
margin: 0 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
border: 2px dashed #848484;
background-color: #dedede;
padding: 20px;
}
.column-block:first-child {
margin-left: 0;
}
.column-block:last-child {
margin-right: 0;
}
.row-block .each-draggable-item {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 10px;
padding-left: 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
margin-bottom: 0;
}
.gu-mirror {
cursor: grabbing;
}
.container .ex-moved {
background-color: #e74c3c;
}
.container.ex-over {
background-color: rgba(255, 255, 255, 0.3);
}
.handle {
background-color: rgba(0, 0, 0, 0.4);
cursor: move;
margin-right: 5px;
padding: 0 5px;
}
.column-block h5 {
margin: 0;
}
/* .gu-mirror {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
position: fixed !important;
margin: 0 !important;
z-index: 9999 !important;
opacity: 1;
}
.gu-hide {
display: none !important;
}
.gu-unselectable {
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
}
.gu-transit {
opacity: 0.4;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
} */
.gu-transit {
opacity: 0.4;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
transition: .3s ease-out;
}
.container {
width: 100%;
}
.bloc {
width: 100%;
border: 2px dashed #848484;
background: #ffefef;
margin-bottom: 20px;
padding: 20px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
.bloc--inner {
margin: 0 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
border: 2px dashed #848484;
background-color: #d4ecff;
padding: 20px;
}
.bloc--inner:first-child {
margin-left: 0;
}
.bloc--inner:last-child {
margin-right: 0;
}
.bloc--inner .bloc {
margin: 0;
}
<div class="wrapper">
<div class="main-content">
<div class="header">
<button class="add-row" onclick="addRow()">Add Row +</button>
<button class="add-column" onclick="addCol()">Add Column +</button>
</div>
<div class="content-box" id="main-container">
<div class="container" id="contentBox"></div>
</div>
</div>
</div>
Perhaps I have this backwards - having re-read the question.
If the process is to be initialised using the button to determine what is to be added when the user clicks within the target area then perhaps this is better than the previous which does seem backwards to the perceived mode of operation.
var i = 0;
var j = 0;
let bRow=false;
let bCol=false;
let parent=false;
let container=document.querySelector('#main-container > .container');
let header=document.querySelector('.header');
container.addEventListener('click',e=>{
parent=e.target;
if(bRow)addRow(e);
if(bCol)addCol(e);
});
header.addEventListener('click',e=>{
bRow=false;
bCol=false;
if( e.target.className=='add-row' )bRow=true;
if( e.target.className=='add-column' )bCol=true;
});
container.addEventListener('contextmenu',e=>{
e.preventDefault();
try{
if( parent )parent.removeChild( e.target );
}catch(err){
console.clear();
console.log(err.message);
}
});
function addRow(e) {
i++;
const row = document.createElement('div');
row.className='bloc';
row.id = `b${i}`;
parent.append( row );
bRow=false;
return row;
}
function addCol(e) {
j++;
const col=document.createElement('div');
col.className='bloc--inner';
col.id = `c${j}`;
parent.append( col );
return col;
}
* {
box-sizing: border-box;
}
/*
to ensure user can see contentBox initially
*/
.container{
border:2px dashed fuchsia;
background:silver;
padding:1rem
}
.bloc:after,
.bloc--inner:after{
content:attr(id)
}
.wrapper {
float: left;
width: 100%;
height: 100vh;
}
body {
padding: 0;
margin: 0;
position: relative;
}
.main-content {
float: left;
width: calc(100%);
height: 100%;
background: #fafafa;
}
.header {
height: 60px;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0 20px;
}
.content-box {
width: 100%;
height: calc(100% - 60px);
padding: 15px;
}
button {
background: #000;
border: 0;
padding: 0 20px;
height: 40px;
margin-left: 10px;
font-weight: 600;
color: white;
cursor: pointer;
}
.row-block {
width: 100%;
border: 2px dashed #848484;
padding: 20px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-bottom: 20px;
}
.row-block:hover {
border-color: #2654d1;
}
.column-block {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 10px;
padding-left: 10px;
margin: 0 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
border: 2px dashed #848484;
background-color: #dedede;
padding: 20px;
}
.column-block:first-child {
margin-left: 0;
}
.column-block:last-child {
margin-right: 0;
}
.row-block .each-draggable-item {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 10px;
padding-left: 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
margin-bottom: 0;
}
.gu-mirror {
cursor: grabbing;
}
.container .ex-moved {
background-color: #e74c3c;
}
.container.ex-over {
background-color: rgba(255, 255, 255, 0.3);
}
.handle {
background-color: rgba(0, 0, 0, 0.4);
cursor: move;
margin-right: 5px;
padding: 0 5px;
}
.column-block h5 {
margin: 0;
}
/* .gu-mirror {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
position: fixed !important;
margin: 0 !important;
z-index: 9999 !important;
opacity: 1;
}
.gu-hide {
display: none !important;
}
.gu-unselectable {
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
}
.gu-transit {
opacity: 0.4;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
} */
.gu-transit {
opacity: 0.4;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
transition: .3s ease-out;
}
.container {
width: 100%;
}
.bloc {
width: 100%;
border: 2px dashed #848484;
background: #ffefef;
margin-bottom: 20px;
padding: 20px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
.bloc--inner {
margin: 0 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
border: 2px dashed #848484;
background-color: #d4ecff;
padding: 20px;
}
.bloc--inner:first-child {
margin-left: 0;
}
.bloc--inner:last-child {
margin-right: 0;
}
.bloc--inner .bloc {
margin: 0;
}
<div class="wrapper">
<div class="main-content">
<div class="header">
<button class="add-row">Add Row +</button>
<button class="add-column">Add Column +</button>
</div>
<div class="content-box" id="main-container">
<div class="container" id="contentBox"></div>
</div>
</div>
</div>
To limit the number of rows that can be added to one can be achieved by setting bRow=false
at the end of the addRow
function. A further enhancement might be to ensure that columns can only be added within rows - probably using a class
attribute when adding the column would be a suitable solution so that you check if the parent does not contain that class etc
Adjustable limitation for rows/cols and sanity checks to ensure that rows are not added within other rows and similar for cols.
let bRow = false;
let bCol = false;
window.bLimitRows = true;
window.bLimitCols = false;
let parent = false;
let container = document.querySelector('#main-container > .container');
let checkboxes = document.querySelector('div.chkbx');
let header = document.querySelector('.header');
let togglebttns=(e)=>{
resetbttns();
e.target.classList.add('active');
return true;
};
let resetbttns=()=>{
header.querySelectorAll('button').forEach(bttn => bttn.classList.remove('active'));
};
container.addEventListener('click',e=>{
parent = e.target;
if( bRow ) addRow(e);
if( bCol ) addCol(e);
});
header.addEventListener('click',e=>{
bRow = false;
bCol = false;
if (e.target.className == 'add-row') bRow = true;
if (e.target.className == 'add-column') bCol = true;
return togglebttns(e);
});
checkboxes.addEventListener('click',e=>{
window[e.target.name] = e.target.checked;
});
container.addEventListener('contextmenu',e=>{
e.preventDefault();
try {
if (parent) parent.removeChild(e.target);
} catch (err) {
console.clear();
console.log(err.message);
}
});
function addRow(e) {
if ( e.target.classList.contains('bloc') ) return;
let row = document.createElement('div');
row.className = 'bloc';
row.dataset.label = 'R';
parent.append(row);
if (bLimitRows) {
bRow = false;
resetbttns();
}
return row;
}
function addCol(e) {
if ( e.target.classList.contains('bloc--inner') || e.target == container ) return;
let col = document.createElement('div');
col.className = 'bloc--inner';
col.dataset.label = 'C';
parent.append(col);
if (bLimitCols) {
bCol = false;
resetbttns();
}
return col;
}
* {
box-sizing: border-box;
}
/*
to ensure user can see contentBox initially
*/
.container {
border: 2px dashed black;
background: silver;
padding: 1rem
}
.bloc:before {
position: relative;
content: attr(data-label)counter(row);
top: calc(50% - 1rem);
left: -2rem;
padding: 0.25rem;
background: yellow;
border: 2px solid black;
max-height: 1rem;
}
.bloc--inner:before {
position: relative;
content: attr(data-label)counter(col);
top: -2rem;
left: calc(50% - 2rem);
padding: 0.25rem;
background: lime;
border: 2px solid black;
max-height: 1rem;
}
.active {
background: lime;
color: black;
}
.wrapper {
float: left;
width: 100%;
height: 100vh;
}
body {
padding: 0;
margin: 0;
position: relative;
counter-reset: row;
counter-reset: col;
}
.main-content {
float: left;
width: calc(100%);
height: 100%;
background: #fafafa;
}
.header {
height: 60px;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0 20px;
}
.content-box {
width: 100%;
height: calc(100% - 60px);
padding: 15px;
}
button {
background: #000;
border: 0;
padding: 0 20px;
height: 40px;
margin-left: 10px;
font-weight: 600;
color: white;
cursor: pointer;
}
.row-block {
width: 100%;
border: 2px dashed #848484;
padding: 20px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-bottom: 20px;
}
.row-block:hover {
border-color: #2654d1;
}
.column-block {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 10px;
padding-left: 10px;
margin: 0 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
border: 2px dashed #848484;
background-color: #dedede;
padding: 20px;
}
.column-block:first-child {
margin-left: 0;
}
.column-block:last-child {
margin-right: 0;
}
.row-block .each-draggable-item {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 10px;
padding-left: 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
margin-bottom: 0;
}
.gu-mirror {
cursor: grabbing;
}
.container .ex-moved {
background-color: #e74c3c;
}
.container.ex-over {
background-color: rgba(255, 255, 255, 0.3);
}
.handle {
background-color: rgba(0, 0, 0, 0.4);
cursor: move;
margin-right: 5px;
padding: 0 5px;
}
.column-block h5 {
margin: 0;
}
.gu-transit {
opacity: 0.4;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
transition: .3s ease-out;
}
.container {
width: 100%;
}
.bloc {
width: 100%;
border: 2px dashed #848484;
background: #ffefef;
margin-bottom: 20px;
padding: 20px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
counter-increment: row;
}
.bloc--inner {
margin: 0 10px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
border: 2px dashed #848484;
background-color: #d4ecff;
padding: 20px;
counter-increment: col;
}
.bloc--inner:first-child {
margin-left: 0;
}
.bloc--inner:last-child {
margin-right: 0;
}
.bloc--inner .bloc {
margin: 0;
}
<div class='wrapper'>
<div class='main-content'>
<div class='chkbx'>
<label>Limit Rows<input type='checkbox' name='bLimitRows' value=1 checked></label>
<label>Limit Cols<input type='checkbox' name='bLimitCols' value=1></label>
</div>
<div class='header'>
<button class='add-row'>Add Row +</button>
<button class='add-column'>Add Column +</button>
</div>
<div class='content-box' id='main-container'>
<div class='container' id='contentBox'></div>
</div>
</div>
</div>
Answered By - Professor Abronsius
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.