JQuery - Clone DIV with button duplicates incorrectly - javascript

Fairly new to programming in general, so this might not be pretty. My problem is when I click the button in the html (Fiddle)
$(document).ready(function() {
$("button").click(function() {
$(".groupcontainer").clone().appendTo(".groupcontainer");
});
});
it will duplicate the first time perfectly. Then, as I keep clicking it, the div will duplicate exponentially and the format gets messy. Also, when it does add to the webpage, the parent div won't expand vertically to allow for the duplicates.
Need one duplicate each time the button is pressed (append to itself, if possible???)
When it's duplicated multiple times, need the parent div to expand with it.
I'm assuming #1 is because I'm using .groupcontainer to clone and appending it to itself - is that an issue? Can someone explain how I would clone .groupcontainer and have it append directly below itself? I've looked around but not seeing the same issue I'm having.
As for #2, does appending this way not allow the parent div to expand?
Am I so far off you want to laugh??

I suggest using a combination of .closest() and .parent() like so (also note my use of the flags for .clone()):
$(document).ready(function() {
$("button").click(function() {
var target = $(this).closest(".groupcontainer");
target.clone(true, true).appendTo(target.parent());
// alternatively you can also use .insertAfter() to
// place the clone after the cloned element rather
// than at the end of all cloned elements
// https://api.jquery.com/insertAfter/
/* target.clone(true, true).insertAfter(target); */
});
});
.groupcontainer {
background-color: white;
height: 225px;
float: left;
margin-top: 10px;
}
.group {
font-family: Arial;
margin-right: 20px;
font-size: 12px;
float: left;
background-color: black;
padding: 2px;
color: white;
clear: both;
display: inline-block;
}
.quantity {
font-family: Arial;
font-size: 12px;
float: left;
background-color: black;
padding: 2px;
display: inline-block;
color: white;
}
.system {
float: left;
background-color: black;
padding: 2px;
display: inline-block;
color: white;
font-family: Arial;
font-size: 12px;
}
.total {
float: left;
background-color: black;
padding: 2px;
display: inline-block;
color: white;
font-family: Arial;
font-size: 12px;
}
.specs {
float: left;
width: 648px;
min-height: 50px;
border-left: 1px solid black;
border-right: 1px solid black;
border-bottom: 1px solid black;
clear: both;
}
.specs table {
width: 650px !important;
}
.specs table tr {
background-color: white !important;
}
.specs table tr td {
font-family: Arial !important;
font-size: 9px !important;
padding: 0px !important;
margin: 0px !important;
color: black !important;
border-bottom: 1px solid black;
}
.specs table tr td span {
color: black !important;
font-family: Arial !important;
font-size: 9px !important;
padding: 0px !important;
margin: 0px !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="groupcontainer">
<div class="group">
<label for="exampleInputText">Group: </label>
<input type="text" name="group_1" id="group_1" onchange="updateDue()" />
</div>
<div class="quantity">
<label for="exampleInputText">Quantity: </label>
<input type="text" name="quantity1" id="quantity1" onchange="updateDue()" />
</div>
<div class="total">
<label for="exampleInputText">System Price:</label>
<input type="text" name="systemprice" id="systemprice" onchange="updateDue()" />
</div>
<div class="system">
<label for="exampleInputText">Group Total:
<script type="text/javascript">
// Library ready to use:
accounting.formatMoney(5318008);
</script>
</label>
<input type="text" name="grouptotal" id="grouptotal" onchange="updateDue()" />
</div>
<!--begin the specs here-->
<div class="specs">
<p>This is a paragraph.</p>
<p>This is another paragraph.</p>
<button>Clone all p elements, and append them to the body element</button>
</div>
</div>

Wanted to update this in case someone else sees it. In the end, the best answer:
$('#clone').click(function() {
var target = $('.groupcontainer:last');
target.clone(true, true).insertAfter(target);
});
$(.groupcontainer:last) instead of $(this).closest(".groupcontainer") worked nicely because there was no restriction on where the button is. I neglected to mention in the question that I planned on moving the button.

You are selecting the whole class .groupcontainer and $(".groupcontainer") will actully return you an array with all elements from this class. Why don't you try selecting an element by it's Id. This way you will select only one element and cloning it shouldn't be a probelm.

The problem is that $('.groupcontainer') grabs all elements with a class of groupcontainer. You can grab the most recent one by using .last() then use .parent() to get the parent of the .groupcontainers and append to that.
var $groupContainer = $('.groupcontainer');
$groupContainer.last().clone().appendTo($groupContainer.parent());

You need to define the first instance of .groupcontainer as the page loads. This will find that single group container and make it a variable.
Then when you click, it will append a new (single instance) group container to your container.
$(document).ready(function(){
var clonedGroupContainer = $('.groupcontainer').clone();
$('.groupcontainer').click(function(){
$(this).append(clonedGroupContainer);
});
});
UPDATE
Because we're using a single instance of a clone, the DOM thinks there's only one instance and basically it's just moving the clone around (even though it's going to the same place).
So what we have to do is create the clone of the first element right off the bat, then append that to wherever (I just appended to the body for ease) and then we hide it. It doesn't matter where it is because the element will be hidden (just don't clone it to itself). Then every time we click, it creates a NEW clone of that object and we can manipulate that new clone every time.
$(document).ready(function(){
var clonedGroupContainer = $('.groupcontainer').clone();
$('body').append(clonedGroupContainer);
clonedGroupContainer.addClass('clone').hide();
$(document).on('click', '.groupcontainer', function(){
var clonedGroupContainer2 = $('.clone').clone();
$(this).append(clonedGroupContainer2);
clonedGroupContainer2.removeClass('clone').show();
});
});

the time you select the container inside the click handler is essential.
On the first click, there's only one container and you clone it and append it to itself.
With the second click you have two containers. You select both, and append both to themselves, leading to an exponential behaviour.
Restrict your selector to only one or store your first container in a reference variable.
$(document).ready(function() {
var $container = $('.groupcontainer');
$container.find('button').click(function() {
$container.clone().appendTo($container);
}
});

Related

Placeholder for contenteditable div with minimal JS

I created a div tag with the contenteditable attribute.
I want to put the placeholder in here, and I found the following code.
[contenteditable=true]:empty:before {
content: attr(placeholder);
display: block;
/* For Firefox */
}
<div class="test" contenteditable="true" placeholder="test"></div>
In a chromium-based engine, it looks like it's working. But I heard there is an error here that requires JavaScript. I couldn't find the error. Can you tell me what the problem is?
I'm also not sure that content:attr(); is the web standard in css. Is it a standardized CSS property?
The problem is that a <br> is automatically inserted inside a contenteditable div when it is empty. I think that they added <br> to prevent it from collapsing. Here's where they discussed this: Bugzilla.
Here's an example of the collapse prevention I mentioned. You can see that, initially, div has 0 height. However, you can still focus on it. Try typing, then erasing everything. Browser automatically inserts <br> to prevent it from returning to 0 height by adding a <br> which is one line-height high.
div {
border: 1px solid black;
}
<div contenteditable="true" data-placeholder="Test"></div>
So we can simply use <span>, which does not insert a random <br>, instead of <div> to do what you want like so. Try typing, then erasing the characters. The placeholder will be there exactly as you want it to be.
* {
box-sizing: border-box;
}
span {
display: block;
width: 100%;
border: 1px solid black;
border-radius: 5px;
font-family: sans-serif;
padding: 10px;
cursor: text;
}
span:empty::before {
content: attr(data-placeholder);
display: block;
height: 100%;
color: #00000066;
}
<span contenteditable="true" data-placeholder="Test"></span>
If you really have to use div, then you can erase the <br> manually using JS:
const editable = document.querySelector('#editable')
editable.addEventListener('keyup', e => {
if (editable.innerText === '\n') editable.innerHTML = ''
})
* {
box-sizing: border-box;
}
#editable {
display: block;
width: 100%;
border: 1px solid black;
border-radius: 5px;
font-family: sans-serif;
padding: 10px;
cursor: text;
}
div:empty::before {
content: attr(data-placeholder);
display: block;
height: 100%;
color: #00000066;
}
<div id="editable" contenteditable="true" data-placeholder="Test"></div>
Using attr() function in CSS with content is not experimental. With other CSS properties like color, though, it is still experimental. Read further on this MDN page.
In .html
<div placeholder="Write your message.." contenteditable class="form-control edit-box holder"></div>
In .css
.holder:before {
content: attr(placeholder);
color: lightgray;
display: block;
position:absolute;
font-family: "Campton", sans-serif;
}
This solution worked for me.
It works on Firefox too. I think I found the "error" that may require the supposed Javascript. Try typing in the div, then delete all of it by CTRL+A backspace; the placeholder won't come back because there's a <br> the browser has automatically inserted (<p></p> in other browsers).
The content property and attr(...) has been standard since IE8, so it's fine.

Apply styling only on the text inside a DIV

I'm having a div in HTML which is dynamically creating from the server side. I want to apply css in HTML(front-end) only on that div if and only if its having some-content. If it doesn't have any content then I have no need to apply the new styling.
The sample of HTML code is:
<div class="attr-marker">
Some-text-content <!-- Apply New Styling on it -->
</div>
<div class="attr-marker">
<!-- No need of new styling -->
</div>
<div class="attr-marker">
<!-- No need of new styling -->
<i class="fas fa-car" style="color:#d42424;font-size:px"></i>
</div>
And the CSS which I tried but failed is:
.attr-marker text {
display: block;
width: 12px;
height: 12px;
border-radius: 50%;
line-height: 12px;
font-size: 9px;
text-align: center;
background: #000;
color: #fff;
}
I can achieve it by using javascript but I want purely CSS solution so it'll help me to minimize the code.
You can set default style for empty div by using :empty pseudo selector. And then for regular div, just set the style as given above.
Or you can use :not(:empty) Pseudo Selector to set the style for the div that is not empty.
Here's an example:
.attr-marker:not(:empty) {
display: block;
width: 12px;
height: 12px;
border-radius: 50%;
line-height: 12px;
font-size: 9px;
text-align: center;
background: #000;
color: #fff;
}
Let me know in case you have any questions.
Regards,
AJ
You can use the :empty pseudo-class. However your server will need to output the .attr-marker div with no whitespace.
Like...
<div class="attr-marker"></div>
not
<div class="attr-marker">
</div>
And then the css would be,
.attr-marker:empty {
display: block;
width: 12px;
height: 12px;
border-radius: 50%;
line-height: 12px;
font-size: 9px;
text-align: center;
background: #000;
color: #fff;
}
Additional reading, https://developer.mozilla.org/en-US/docs/Web/CSS/:empty
Writing .attr-marker text { } means you want to access child elements with tag text of class attr-maker. No such tag exists in HTML.
There are specific CSS text and CSS font properties which work only on text. They are to be used in the text's parent element (in your case div with class name attr-marker):
.attr-marker {
/* text properties */
/* some other properties */
}
Properties like display: block;, width: 12px;, height: 12px; and so on, won't work on text.
That being said, you don't need to worry whether your CSS properties will be applied to the text or to the whole div. If you're using the right properties, you can be sure they are only applied to the text.
As for the content(text) presence, you don't need to worry about it. If there is no text, CSS won't change anything.
Either add another class to that div from the server side if it will send content or wrap content with another element and give it some styling.
Edit:
If you know exact position of your element then you can select it with nth-child pseudo-class:
.attr-marker:nth-child(1):not(:empty) {
border: 1px solid #333;
background-color: yellow;
}
If these markers are block rendered elements, the browser should not display them, unless they have content, therefore you can trust the browser to not render the elements with no content, use the max-width and max-height properties below:
.attr-marker {
display: block;
max-width: 12px;
max-height: 12px;
border-radius: 50%;
line-height: 12px;
font-size: 9px;
text-align: center;
background: #000;
color: #fff;
/*If required*/
overflow:hidden
}

Implementing a parent selector in CSS with jQuery that applies automatically to new elements in DOM

CSS does not support parent selectors, e.g. "select all <p> that contain an <img>".
One solution proposed here is to use jQuery, for example:
$('#parent:has(#child)').addClass('my-special-class');
However, I have a <div> that is periodically updated with new content, and I need to keep reapplying the my-special-class to new elements that match the selector '#parent:has(#child)' inside that <div>.
How could one do that?
I am styling a third-party plugin so I don't have much control over its styling, events and so on.
One solution is to bind the DOMSubtreeModified event on the container div and add your code inside.
$('.container').on("DOMSubtreeModified",function(){
$('.parent:has(.child)').addClass('special-child');
});
// find elements
var parent = $("#parent")
var button = $("button")
// handle click and add class
button.on("click", function() {
const el = '<div class="parent"><p class="child">Hello World</p></div>';
parent.after(el);
})
$(function() {
$('.parent:has(.child)').addClass('special-child');
$('.continer').on("DOMSubtreeModified", function() {
$('.parent:has(.child)').addClass('special-child');
});
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
.child {
background: #fff;
border-radius: 4px;
padding: 10px;
font-size: 25px;
text-align: center;
transition: all 0.2s;
margin: 4px auto;
width: 300px;
}
button {
background: #0084ff;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
.special-child {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<div class="continer">
<div class="parent" id="parent">
<p class="child">Hello World</p>
</div>
</div>
<button>Add Child</button>
If you add the following jquery and just one class, it will work like :visited:
$("div.my-div").click(function(){
$(this).addClass("visited");
});
And just add one class to the css:
.visited:hover{
outline: 2px solid orange;
}
If you add this code with the current code of yours, you will get the same functionality as the one for :visited.
Here is a fiddle that I tried on your code:
https://jsfiddle.net/thisisdg/27srmuy6/

Show/Hide divs with jQuery?

First off, there's are many questions similar to mine but I haven't found an answer I've been able to use yet. I have a page that shows a login form when you enter. I also have a register form that I want hidden. With a click I want the login form replaced with the register form.
I've tried this code that I found and with a little help this could work, it has a nice smooth transition but it shows both elements from the start.
$(function() {
$('a').click(function() {
div = $(this).attr('href'); //grab #one, #two which correspond to the div id we're targeting
paragraph = $(div); //store each div in a variable for later use
$('#two').hide();
$('div').hide('grey-bg'); //remove any greyed backgrounds
$(paragraph).show('grey-bg'); //add grey background to clicked element
});
});
a {
text-decoration: none;
}
#one {
margin: 10px;
padding: 20px;
border: 1px solid #000;
}
#two {
margin: 10px;
padding: 20px;
border: 1px solid #000;
}
.grey-bg {
background-color: #cccccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
First Link<br />
Second Link
<div id="one">
This is the first paragraph.
</div>
<div id="two">
This is the second paragraph.
</div>
You can see it working here: https://codepen.io/raazxplorer/pen/rVKzNp
All I have done with this is changed removeClass and toggleClass to hide/show.
add display:none; in #two
#two {
margin: 10px;
padding: 20px;
border: 1px solid #000;
display:none;
}
$(function() {
$('a').click(function() {
div = $(this).attr('href'); //grab #one, #two which correspond to the div id we're targeting
paragraph = $(div); //store each div in a variable for later use
$('#two').hide();
$('div').hide('grey-bg'); //remove any greyed backgrounds
$(paragraph).show('grey-bg'); //add grey background to clicked element
});
});
a {
text-decoration: none;
}
#one {
margin: 10px;
padding: 20px;
border: 1px solid #000;
}
#two {
margin: 10px;
padding: 20px;
border: 1px solid #000;
display:none;
}
.grey-bg {
background-color: #cccccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
First Link<br />
Second Link
<div id="one">
This is the first paragraph.
</div>
<div id="two">
This is the second paragraph.
</div>
Just Hide one of the div on page load.
What you need is:
$(document).ready(function(){
$("#two").hide();
});
Read more about (document).ready()
I made a JSFiddle, i did not put the (document).ready() part in it because its not necessary in JSFiddle.
But you can add it above $("#two").hide(); if you wish. It will also work.

Remove shadow from a button when its active

I have a button with javascript attached. When you click the button a hidden box will appear, when you click another one, the first box gets replaced with the second and so on. When my button is active, when the box is visible, it gets a shadow around. And i donĀ“t want that! I tried to use the following css codes:
.nav > button{
width: auto;
font-family: 'OpenSansBold';
color: #000;
padding: 3px;
border: none;
margin-right: 10px;
margin-top: 5px;
font-size: 15px;
text-align: left;
background-color: #fff;
}
button:hover{
cursor: pointer;
border: none;
color: #7b1a2c;
}
button:visited{
font-family: 'OpenSansBold';
box-shadow: none;
}
button:active{
box-shadow: none;
}
But with no luck. Is there another CSS code for buttons when its active?
I have no clue about javascript, just copy pasted this thing. Maybe this is something that can be fixed in the js code? Just in case, I can show you guys:
$('div.box').slice(1).addClass('hidden');
$('.nav').children('button').on('click', function(){
// console.log('klikk');
$(this).data('content');
$('.box').not('hidden').addClass('hidden');
$( $(this).data('content')).removeClass('hidden');
});
Maybe you talk about outline property or :focus pseudo-class?
Try this one:
button:active, button:focus {
box-shadow: none;
outline: 0;
}
To give you a working example, play around with the following snippet, I think this behaves like you would want it to.
To completely remove the shadow, just remove the second JS rule.
// :active rules
$('button').on('mousedown', function () {
$(this).css('box-shadow', 'none');
});
// :visited rules
$('button').on('mouseup', function () {
$(this).css('box-shadow', '10px 10px 5px #888888');
});
button {
width: 300px;
height: 100px;
background-color: yellow;
box-shadow: 10px 10px 5px #888888;
}
<script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
<body>
<button>test</button>
</body>

Categories