Why does draggable not work for dynamically created elements? - javascript

My draggable elements are created dynamically. every time I add an item, I call draggable() again. They get draggable classes, but don't drag.
When writing draggable to the debug console, it successfully works with non-dynamic elements.
$(window).on('load', function () {
var item = '<div class="item"></div>';
$field.append(item);
dragItems();
});
function dragItems() {
var $items = $('.item');
$items.draggable();
}
In the inspector, I see that the drag classes are created, but the movement does not occur.

Consider the following example.
$(function() {
function dragItems(dObj) {
dObj.draggable({
containment: "parent"
});
}
var item = '<div class="item"></div>';
$("#field").append(item);
dragItems($("#field .item"));
});
#field {
width: 400px;
height: 200px;
background: #CFC;
}
.item {
width: 100px;
height: 100px;
background: #CCC;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="field"></div>
I suspect there is more code to your example. This is wrapped in $(function(){}); which will wait until the document is ready. Similar to $(window).on('load').
The function is setup to accept a jQuery Object and assign Draggable to the Object. So you have to pass it the $("#field .item") object.
Now if you had created the object first, could be a little less code. Your current code is not creating an object but injecting HTML string by append. Consider the following.
$(function() {
function dragItems() {
$("#field .item").draggable({
containment: "parent"
});
}
var item = $("<div>", {
class: "item"
});
$("#field").append(item);
dragItems();
});
#field {
width: 400px;
height: 200px;
background: #CFC;
}
.item {
width: 100px;
height: 100px;
background: #CCC;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="field"></div>
This, I think, is more like what you want to do, where you just make all .item elements draggable. You can use either method. I would just make sure you create an Object one way or another to use with Dragable.
Hope that helps.

Related

Child Visibility Affects Parent Visibility

I'm having a weird issue when setting a child container to visibility: visible via JavaScript in the $(document).ready function.
Here's the problem:
I'm having a parent element, that has bootstraps helperclass class="d-none".
I now want to set the CSS of the child of this element to visibility: visible.
The problem is that, as long as the $(document).ready function is running, the parent and its child are visible.
This means that some weird stuff is going on, since wrapping a visible element in a hidden element should always show nothing.
But apparently it does show both the parent and the child.
Does anybody know how to fix this?
TO BE SPECIFIC HERE:
I want to call the $(document).ready function
I don't want to see the child, nor the parent when calling the function, as this following code does also not show the child nor the parent because the parent has "d-none"
.parent{
width: 100px;
height: 100px;
}
.child{
width: 50px;
height: 50px;
visibility: visible;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<div class="parent d-none">
<div calss="child">
</div>
</div>
Why can the parent be seen in the below snippet, when setting the visibility of the child via js?
The parent should still have "d-none", and therefore all its children should also not be visible, or what am I understanding wrong here?
To reproduce this issue, copy the lower code snippet to your answer and hit run a few times, you will see the yellow and red rectangles show up for a short amount of time, before they are actually not visible anymore.
$(document).ready(function() {
$(".visi").css("visibility", "visible");
});
.d-none {
background-color: red;
width: 100px;
height: 100px;
}
.visi {
background-color: yellow;
width: 50px;
height: 50px;
}
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<div class="d-none">
<div class="visi" style="visibility: visible;"></div>
</div>
Let me start out by saying that I probably do not understand 100% of what you are trying explain. This is what I have gathered please inform me of any differences:
Your while loop was an attempt to reveal the divs at a future time.
loops are way too fast to be any use as a timer you need setTimeout()
JavaScript is asynchronous so if you plan to reveal one div and then the next (I'm guessing here because you weren't really specific), you'll get one possibly finishing before another or possibly way later. You can make times synchronous by using async function and await keyword.
asynchronous: A set to start at 2secs and B set to start at 2.5secs they'll both end possibly at the same time.
synchronous: A starts at 2secs and ends B stars 2.5secs later.
You right to assume that a child is is hidden if the parent is hidden except if the parent has visibility:hidden and a child has visibility: visible the parent will remain hidden and the child will be visible.
Bootstrap class .d-none is entirely different. It is display:none; which practically removes the element from all but HTML. With visibility:hidden the element still takes space. An element with display:none doesn't take up space.
function reveal(selector) {
$(selector).css('visibility', 'visible')
}
const selectors = ['.child', '.parent'];
const times = [3000, 5500];
async function sync(selectors, times) {
const showChild = () => {
return new Promise(resolve => {
setTimeout(() => resolve(reveal(selectors[0])), times[0]);
});
}
const showParent = () => {
return new Promise(resolve => {
setTimeout(() => resolve(reveal(selectors[1])), times[1]);
});
}
await showChild();
await showParent();
}
sync(selectors, times);
.parent {
visibility: hidden;
background-color: red;
width: 100px;
height: 100px;
}
.child {
visibility: hidden;
background-color: yellow;
width: 50px;
height: 50px;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous">
<div class="parent">
<div class="child"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
Check this code. I fixed some parts.
function myFunction(){
if (1 === 1) {
$(".visi").css("visibility", "visible");
var i = 0;
while(i < 100){
console.log(i++);
}
}
}
.visi {
background-color: yellow;
width: 50px;
height: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="d-none">
<div class="visi" style="visibility: hidden;" ></div>
</div>
<button onclick="myFunction()">Click me</button>
you can set the visibility to hidden at the beginning and then set it to visible

JS function doesn't change box color

JS just refuses to do anything - doesn't show console.log, doesn't show any errors, doesn't do anything.
JS just doesn't give any signs of life really - I tried making document.getelementbyid(box1) and ("#box") and ("box") because of people on the internet use all these and it works.
Tried to make events embedded in HTML to call the function, tried to call the function on window.onload, etc.
Tried changing text and color and size and margins - nothing works. And there is sometimes a null error - meaning that JS can't get the style value for some reason.
var box = document.getElementById("#box1");
function changeColor() {
var box = document.getElementById("#box1");
box.style.backgroundColor = 'red';
}
#box1 {
height: 100px;
width: 100px;
background-color: #B9E257;
}
#box2 {
height: 100px;
width: 100px;
background-color: #69ADE1;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="N.css" type="text/css">
</head>
<body>
<div id="box1">1</div>
<div id="box2">2</div>
<button onclick="changeColor()">Go!</button>
<script src="N.js" type="text/javascript"></script>
</body>
</html>
Why on earth would it not work?
The Document method getElementById() returns an Element object
representing the element whose id property matches the specified
string. Since element IDs are required to be unique if specified,
they're a useful way to get access to a specific element quickly.
For more info visit the docs
The ID is case-sensitive string which is unique within the document;
Please check the running example below:
function changeColor() {
var box = document.getElementById("box1");
console.log(box);
box.style.backgroundColor = 'red';
}
#box1 {
height: 100px;
width: 100px;
background-color: #B9E257;
}
#box2 {
height: 100px;
width: 100px;
background-color: #69ADE1;
}
<head>
<link rel="stylesheet" href="N.css" type="text/css">
</head>
<body>
<div id="box1">1</div>
<div id="box2">2</div>
<button onclick="changeColor()">Go!</button>
<script src="N.js" type="text/javascript"></script>
</body>
Your JS throwing error just because you are using # in document.getElementById which is not allowed. You need to define # for ID in jQuery not in JS.
Here is the updated code. Just only removed # from document.getElementById nothing else I have done in it.
function changeColor() {
var box = document.getElementById("#box1");
box.style.backgroundColor = 'red';
}
#box1 {
height: 100px;
width: 100px;
background-color: #B9E257;
}
#box2 {
height: 100px;
width: 100px;
background-color: #69ADE1;
}
<head>
<link rel="stylesheet" href="N.css" type="text/css">
</head>
<body>
<div id="box1">1</div>
<div id="box2">2</div>
<button onclick="changeColor()">Go!</button>
<script src="N.js" type="text/javascript"></script>
</body>
If you really like that #, then instead of
var box = document.getElementById("#box1");
do
var box = document.querySelector("#box1");

jQuery resizable() for dynamic elements working uptil second-last element but not for the last element

I am creating div elements dynamically, on clicking on duplicate button. the divs are draggable and resizable horizontally. Everytime I create a new div, by clicking on duplicate, the new divs are draggable. But with resizable an unusual behavior is observed. The behavior is all the divs uptil second last div gets the resizable feature, but the most recent(last) doesn't get resizable. I referred the solution given here,
Apply jQueryUI Resizable widget to dynamically created elements. They are using :last and after() methods.
I am not getting how I use it in my case.
Following is my code,
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://code.jquery.com/jquery-3.3.1.js"
integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="
crossorigin="anonymous"></script>
<script
src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"
integrity="sha256-0YPKAwZP7Mp3ALMRVB2i8GXeEndvCq3eSl/WsAl1Ryk="
crossorigin="anonymous"></script>
<script type="text/javascript">
var bar_id = 1;
$(document).ready(function(){
$(".action").draggable({cursor:"move",containment:"#limits"});
$(".action").resizable({handles:"e,w",maxWidth:1300,maxHeight:46,minWidth:100,minHeight:46});
$(document).on('click',".duplicate_btn",function(){
bar_id += 1;
var duplicate_bar = $(this).parent().clone();
duplicate_bar.attr("id","action_"+bar_id);
duplicate_bar.find(".duplicate_btn").attr("id","duplicate_btn_"+bar_id);
$("#limits").append(duplicate_bar);
$(".action").draggable({cursor:"move",containment:"#limits"});
$(".action").resizable({handles:"e,w",maxWidth:1300,maxHeight:46,minWidth:100,minHeight:46});
});
});
</script>
<style type="text/css">
.action{
background-color: #aaa;
height: 46px;
width: 200px;
float:left;
border:2px solid black;
position:absolute;
/*for items inside div*/
display: flex;
align-items: center;
justify-content: center;
}
#limits{
background-color: lavender;
height: 50px;
width: 1300px;
}
</style>
</head>
<body>
<div id="limits">
<div id="action_1" class="action">
<button id="duplicate_btn_1" class="duplicate_btn">Duplicate</button>
</div>
</div>
</body>
</html>
Please help to get the way out. Thank You in advance!.
If you check the DOM inspector after you clone() the element you'll see that it has also copied the .ui-resizable-handle elements which were added to the original element when draggable() and resizable() were called on it.
This is the cause of the issue. You need to remove those elements before you define draggable and resizable on the new element. Also note that you can call those methods on the new instance directly instead of redefining the plugin on all instances of .action. Try this:
var bar_id = 1;
$(document).ready(function() {
defineDragResize($('.action'));
$(document).on('click', ".duplicate_btn", function() {
bar_id += 1;
var $duplicate_bar = $(this).parent().clone().appendTo('#limits')
$duplicate_bar.find('div').remove();
defineDragResize($duplicate_bar);
});
function defineDragResize($el) {
$el.draggable({
cursor: "move",
containment: "#limits"
}).resizable({
handles: "e,w",
maxWidth: 1300,
maxHeight: 46,
minWidth: 100,
minHeight: 46
});
}
});
.action {
background-color: #aaa;
height: 46px;
width: 200px;
float: left;
border: 2px solid black;
position: absolute;
/*for items inside div*/
display: flex;
align-items: center;
justify-content: center;
}
#limits {
background-color: lavender;
height: 50px;
width: 1300px;
}
#limits {
background-color: lavender;
height: 50px;
width: 1300px;
}
<link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js" integrity="sha256-0YPKAwZP7Mp3ALMRVB2i8GXeEndvCq3eSl/WsAl1Ryk=" crossorigin="anonymous"></script>
<div id="limits">
<div class="action">
<button class="duplicate_btn">Duplicate</button>
</div>
</div>
One thing to note is that I removed the dynamic id logic. This is an anti-pattern and should not be used. Use common classes and DOM traversal instead.

jQuery click works only once

I want to create a circle everytime I click the button but the once I click it, it creates a circle but when i click it again nothing happen.
$(document).ready(function() {
var circle = $("<div class='circleClass'></div>");
$(".t-testbody").on("click", "#clickMe", function() {
$(".t-testbody").append(circle);
});
});
.t-testbody {
margin-top: 100px;
margin-left: 50px;
}
.circleClass {
width: 50px;
height: 50px;
border-radius: 100%;
background-color: blue;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="t-testbody">
<div class="circleClass"></div>
<button id="clickMe">Button</button>
</div>
Currently you have created the element and appended it to the div. so second append statement has not effect as the element already exist in the div.
Instead of element use HTML string
var circle = "<div class='circleClass'></div>";
$(".t-testbody").on("click", "#clickMe", function () {
$(".t-testbody").append(circle);
});
DEMO
You can use .clone()
var circle = $("<div class='circleClass'></div>");
$(".t-testbody").on("click", "#clickMe", function () {
$(".t-testbody").append(circle.clone());
});
DEMO
You are defining your HTML element only once, so instead of this
$(document).ready(function() {
var circle = $("<div class='circleClass'></div>"); // Move this into event handler callback
$(".t-testbody").on("click", "#clickMe", function() {
$(".t-testbody").append(circle);
});
});
Do this:
$(document).ready(function() {
$(".t-testbody").on("click", "#clickMe", function() {
var circle = $("<div class='circleClass'></div>"); // Move this here
$(".t-testbody").append(circle);
});
});
What's happening is that jQuery creates the HTML element, then on click it moves that element to the div. When you click it again, it moves that same element into where it just was, giving the illusion that it did nothing, but it just moved it into the position it already was.
When you move the variable declaration into the callback, it will generate a new html element every time you click that element, therefore jQuery will be appending a newly defined element to the div.
circle holds the reference of element being appended. So it has no difference after first click.
You can create circle inside the callback function like this :
$(document).ready(function(){
$(".t-testbody").on("click","#clickMe",function(){
var circle = $("<div class='circleClass'></div>");
$(".t-testbody").append(circle);
});
});
.t-testbody {
margin-top: 100px;
margin-left: 50px;
}
.circleClass {
width: 50px;
height: 50px;
border-radius: 100%;
background-color: blue;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="t-testbody">
<div class="circleClass"></div>
<button id="clickMe">Button</button>
</div>
Demo : http://jsfiddle.net/vikashvverma/ou52j2xn/

jQuery very simple code seems to not work

Here is my jQuery code:
(function() {
var overlay = {
init: function() {
$('<div></div>', {
class: 'overlay'
})
.insertAfter('button');
}
};
overlay.init();
})();
I would expect this to put a div under my button however the HTML that is created contains no div:
<body>
<button>Reveal More Info</button>
</body>
Sorry if this is a newbie question, I have just started learning.
The HTML Head:
<head>
<title>jQuery rules</title>
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<script src="script.js"></script>
<style>
body {
background: yellow;
}
button {
margin: 100px 0 0 200px;
}
div {
display: none;
width: 600px;
height: 400px;
background-color: white;
border-radius: 40px;
position: absolute;
left: 25%;
top: 30%;
}
</style>
</head>
From jQuery documentation, see e.g., http://api.jquery.com/jQuery/#jQuery-html-attributes:
Blockquote
The name "class" must be quoted in the object since it is a JavaScript reserved word, and "className" cannot be used since it refers to the DOM property, not the attribute.
The problem is you are including the script.js in your header which is executing before the button is added to the dom so the insertAfter() will not be able to find the button to insert the div.
The solution here is to use document ready handler, or to insert the script at the bottom of the body(just before </body>)
//dom ready handler
jQuery(function ($) {
var overlay = {
init: function () {
$('<div></div>', {
'class': 'overlay'
}).insertAfter('button');
}
};
overlay.init();
});
Demo: Fiddle

Categories

Resources