JQuery .append() Separate Elements - javascript

I've made a script which adds an image and a textbox to a canvas. In order for the textbox to appear over the image, I need to apply CSS to the image. Therefore I made to separate divs, <img> for the image and <text> for the text.
This creates two problems. When I fist add the image and the text the two elements are considered separate and I can only drag either the image or the text, rather than the two elements at the same time. Furthermore, when I add another image and another textbox the two don't appear on top of each other, rather the text is spawned next to the textbox and the image next to the image.
So my question is this. Is it possible to consolidate these two elements into one and when spawned make them do so, make them do it the same way every time?
Here is my Javascript I made for it.
$(document).ready(function() {
$("#img").draggable();
$("#text").draggable();
});
function addEvent() {
$("#img").append("<img src='Sticky_Note.png'</a>")
$("#text").append(" <textarea name='comments' x-webkit-speech='x-webkit-speech'style='width:380px;height:300px; background: none; border:none; font-size:24px; color:#0033FF;font-family:comic sans ms' />")
}
Should this not be enough information (I'm n00btastic, sorry), I 've attactched a bleeding edge link here.
Thanks for your help!

Try creating a wrapper <div> around your image and text elements, e.g. <div id="#wrapper">. Then you can do the following:
$('#wrapper').draggable();
Your addEvent code would look like:
function addEvent() {
$("#wrapper").append("<img src='Sticky_Note.png'</a>");
$("#wrapper").append(" <textarea name='comments' x-webkit-speech='x-webkit-speech'style='width:380px;height:300px; background: none; border:none; font-size:24px; color:#0033FF;font-family:comic sans ms' />");
}

there's a few issues with your implementation, I'll ignore the basic document issues as I figure you were putting together a quick example :)
When you append a new 'note' it's not individually movable, it's the container that is movable so they just stack up as you're only adding more content to the corkboard container, ie: another textarea/image, then another textarea/image.
I've put up a solution on pastebin here, feel free to have a look, hopefully it helps point you in the right direction.
Actually, i'll embed it too, for posterity
<!DOCTYPE html>
<html>
<head>
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
<style>
#corkboard { position: relative; }
#corkboard textarea { position: absolute; width: 380px; height: 300px; top: 100px; left: 60px; background: none; border: none; font-size: 24px; color: #03f; font-family: 'comic sans ms', serif; }
#corkboard img { position: absolute; }
.corkboard-item {
position: absolute;
float: left;
width: 500px;
height: 500px;
}
</style>
<script>
$( document ).ready( function() {
// Create our corkboard item
//
$corkboard_item = $( '<div></div>' );
$corkboard_item
.addClass( 'corkboard-item' )
.append( '<img src="http://www.bookofsam.com/corkboard/Sticky_Note.png" />' )
.append( '<textarea name="comments" x-webkit-speech="x-webkit-speech">Enter your note</textarea>' );
// Counter goodness
$x = 1;
// Make sure the one we click is always at the top
//
$( 'img, textarea' ).live( 'click', function( e ) {
e.preventDefault();
$( '.corkboard-item' ).each( function() {
$( this ).css({ 'z-index':1 });
});
$( this )
.parent()
.css({
'z-index':2
})
});
// Add one when we click the button
//
$( 'a.add-item' ).live( 'click', function( e ) {
e.preventDefault();
var item = $corkboard_item.clone();
$( item )
.find( 'textarea' )
.attr({
'name' : ( 'comment-' + $x )
});
$x++;
$("#corkboard").append( $( item ).draggable() );
});
});
</script>
</head>
<body>
<p>CORKBOARD TEST - 0.8.555 </p>
<img src='http://www.bookofsam.com/corkboard/Note_Scale.png' align="right" />
<div id="corkboard"></div>
</html>
Thinking about it, I should've really put the 'note' image as a background image on the 'corkboard-item'.
:)
nbsp;

Related

Dynamic mouseenter

I appended a few divs with inside img tags. Every tag has own unique id = "theImg"+i where "i" is number. I want to mouseover on specific img and show the content of span (which also have specific id with number). Here is my code so far but not working.
var j;
document.onmouseover = function(r) {
console.log(r.target.id);
j = r.target.id;
}
$(document).on({
mouseover: function(e){
$("span").show();
},
mouseleave: function(e){
$("span").hide();
}
}, "img#"+j);
If you have a span after every img, maybe it's a good idea to not use JavaScript at all? ;-)
You could use :hover pseudoclass in CSS, making your thing always work reliably.
Consider the following example:
img + span {
display: none;
}
img:hover + span {
display: block;
}
/*/ Optional styles /*/
div {
position: relative;
float: left;
}
div img + span {
position: absolute;
color: #fff;
background: #27ae60;
border: solid 1px #2ecc71;
border-radius: 50px;
z-index: 1;
bottom: 1em;
width: 80%;
left: 50%;
margin-left: -43%;
padding: 2% 3%;
text-align: center;
}
<div>
<img src="https://placehold.it/400x200">
<span>This is an image of a gray rectangle!</span>
</div>
<div>
<img src="https://placehold.it/200x200">
<span>This is an image of a gray square!</span>
</div>
<div>
<img src="https://placekitten.com/g/400/200">
<span>This is an image of a cute kitten inside a rectangle!</span>
</div>
<div>
<img src="https://placekitten.com/g/200/200">
<span>This is an image of even cuter kitten inside a square!</span>
</div>
So the issue is that you are trying to set your handler on a dynamic selector ("img#"+j) but this will not work. For one thing, that equation will be evaluated only once, on page load, when j is undefined.
So you want to do this instead:
target only img tags for your mouse over... Better yet, give your special images all the same css class so you can attach the event handlers only to those. That will be more efficient.
When an image is moused over or out of, grab it's id attribute, extract the number from it, then use that to build a selector for the appropriate span to show.
var get_span_from_image = function(image) {
var image_id = image.attr("id");
var matches = image_id.match(/theImg(\d+)/);
if(matches) return $("theSpan" + matches[1]);
return $(); // nothing found, return an empty jQuery selection
};
$("img").hover(
function() { // mouse over
get_span_from_image($(this)).show();
},
function() { // mouse out
get_span_from_image($(this)).hide();
}
);
Note: There are better ways to "link" two nodes together, but this is just to answer your question with the current structure you have.
UPDATE: Some ideas to link two nodes together
So instead of trying to extract a number from an id attribute, a better way would be to tell either one of the image or span about it's sibling. You could output your html like this, for instance:
<img id="theImg1" data-target="theSpan1" class="hoverable" src="..."/>
....
<span id="theSpan1">...</span>
Of course now your ideas could be anything - you don't have to use numbered values or anything.
Then your hover code becomes quite simply:
var get_span_from_image = function(image) {
var span_id = image.data("target");
return $("#" + span_id);
};
$("img").hover(
function() { // mouse over
get_span_from_image($(this)).show();
},
function() { // mouse out
get_span_from_image($(this)).hide();
}
);
Hope this helps!

Replace DIV with JQuery passing parameters

I'm having a problem here to create a generic function on JQuery for my "boxes".
I have a visible box with contents, but I will have some other boxes(all DIVs) with another contents and forms. It can be just a DIV ou a full scructured content.
For exemple, a structure like this:
| DIV CONTAINER
|---- DIV CONTACT FORM
|---- ---- DIV RESET PASSWORD
|---- DIV RESET PASSWORD
|---- DIV SIGN UP FORM
|---- DIV RULES
|---- TERMS
Right now I'm doing the box exchanging manually like this code:
$( "#contact-form-link" ).on( "click", function()
{
$( "#contact-form-link" ).fadeOut( "normal", function()
{
$( "#reset-password-form" ).fadeIn( "normal" );
});
});
$( "#reset-password-form" ).on( "click", function()
{
$( "#reset-password-form" ).fadeOut( "normal", function()
{
$( "#contact-form-link" ).fadeIn( "normal" );
});
});
It's unecessary so much code!
I would like to create a function with parameters, so, I can call it from a LINK inside any part of the current box.
A function like:
function exchangeBoxes(box_fadeout,box_fadein)
{
$("box_fadeout").on("click", function()
{
$("box_fadeout").fadeOut( "normal", function()
{
$("box_fadein").fadeIn( "normal" );
});
});
};
So this way, I can call this function from a link passing which DIV will fadeOut and which will fadeIn.
I'm in #contact-form and want to change to #reset-password-form?
Click Here
I need to be able to call the function from any link, anywhere on the page, WITHOUT setting a ID or CLASS for the link, only for the DIVS.
I'm using one function inside another so the IN page only loads when the OUT page is done.
ONLY ONE div can be displayed at time. When one fades out, the other one called will fadeIN. Always callig by the ID, never by CLASS.
Any help to create this generic function is welcome!
Thanks!
You can attach the event to parent div, check id of element at click event, pass the element as either first or second parameter to exchangeBoxes depending on the id of the element.
function exchangeBoxes(a, b) {
$(a).fadeOut( "normal", function() {
$(b).fadeIn( "normal" );
});
}
var elems = ["contact-form-link", "reset-password-form"];
$("#container").on("click", "[id]", function(e) {
if (this.id === elems[0]) {
exchangeBoxes("#" + elems[0], "#" + elems[1])
}
if (this.id === elems[1]) {
exchangeBoxes("#" + elems[1], "#" + elems[0])
}
});
or use multiple selectors when assigning click event
var elems = ["contact-form-link", "reset-password-form"];
$("#contact-form-link, #reset-password-form")
.on("click", function(e) {
exchangeBoxes(this, "#"
+ elems.filter(function(id) {return id !== e.target.id})[0])
});
You could attach a class e.g. exchange to your link and use a data attributes to store the ID of the elements you want to fade in and out.
<a class="exchange" href="#" data-out="#contact-form" data-in="#reset-password-form">Click Here</a>
<a class="exchange" href="#" data-out="#reset-password-form" data-in="#contact-form">Click Here</a>
Then attach an event handler
$(".exchange").on("click", function () {
var data = this.dataset;
$(data.out).fadeOut("normal", function () {
$(data.in).fadeIn("normal");
});
});
If you strictly only focusing on those two DIVs, you could also use fadeToggle() without having to use data attributes
$(".exchange").on("click", function () {
$('#contact-form').fadeToggle("normal", function () {
if ($(this).is(':visible')) {
$("#reset-password-form").fadeOut("normal");
} else {
$("#reset-password-form").fadeIn("normal");
}
});
});
In addition to the answer above, you can also acheive this without using inline onclick. I prefer to keep the javascript separate.
Give each link a data-link with the box they link to. e.g.
Go to box 2
Then in js you can pick this up and do the required fade in/out as per the example:
p.s. sorry for the css I'm really bored with nothing better to do.
$(".box a").click(function() {
linkTo = $(this).data("link");
$(this).parent().fadeOut("normal", function() {
$(linkTo).fadeIn();
});
});
body {
background: #333;
color: #ccc;
font-family:sans-serif;
}
.box {
margin: 0 auto;
width: 300px;
border: 1px solid #ccc;
text-align: center;
display:none;
}
.box a {
text-decoration: none;
color: #ccc;
border:1px solid #ccc;
padding: 10px;
margin: 0 0 10px 0;
display: inline-block;
}
.box a:hover {
background: #333;
color: #ccc;
}
#box1 {
background: #CD5C5C;
display:block;
}
#box2 {
background: #6B8E23;
}
#box3 {
background: #6A5ACD;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
<div class="box" id="box1">
<h3 class="title"> I am Box 1 </h3>
Go to box 2
<br>
Go to box 3
</div>
<div class="box" id="box2">
<h3 class="title"> I am Box 2 </h3>
Go to box 1
<br>
Go to box 3
</div>
<div class="box" id="box3">
<h3 class="title"> I am Box 3 </h3>
Go to box 1
<br>
Go to box 2
</div>
</div>
Well, thank you all!
I put all responses together and came up with this:
<div id="contact">
<h3>CONTACT</h3>
<p>My form</p>
Reset Password
About
</div>
<div id="reset" style="display:none">
<h3>RESET</h3>
<p>Reset password form</p>
Back to contact
</div>
<div id="about" style="display:none">
<h3>ABOUT</h3>
<p>Some info.</p>
Back to contact</li>
</div>
And the JQuery very clean:
function exchangeBoxes(a, b)
{
var a = "#" + a;
var b = "#" + b;
$(a).fadeOut( "normal", function()
{
$(b).fadeIn( "normal" );
});
}
Thank you very much, guys!

newly created dom elements cannot be draggable

I'm using jquery and jquery ui to create draggable elements.
i created a small jsfiddle example at https://jsfiddle.net/2j2c8vLc/
that demonstrates what i'm trying to do.
javascript code:
$(function(){
$('body').append('<div id="moshe">hi</div>');
$('#moshe').draggable();
});
in the example i add to the body a div element after document ready event and then trying to make it draggable. the results are that it's not draggable, the classes are added to the element but it seems that it's not enough.
any ideas?
update
more info to clear things up.. i'm trying to move a readonly text input.
i created new jsfiddle at http://jsfiddle.net/70f3dbLh/2/
with the following javascript code:
$(document).ready(function(){
$("<div>").attr("id", "moshe").html("<input readonly type=\"text\"></input>").appendTo("body").draggable();
});
as you can see here.. the text input inside the div is not draggable
i tried to create another example of trying to create a text input without a div and make it draggable.. same results. it's not draggable.
jsfiddle at http://jsfiddle.net/70f3dbLh/3/
javascript code:
$(document).ready(function(){
$("<input readonly value=\"aaa\" type=\"text\"></input>").attr("id", "moshe").appendTo("body").draggable();
});
Use following jsfiddle: http://jsfiddle.net/70f3dbLh/1/ and look at this: http://jsfiddle.net/70f3dbLh/1/show/
The code is something like
$(document).ready(function(){
$("<div>").attr("id", "moshe").html("hi").appendTo("body").draggable();
});
It is then draggable.
Update on your update
I updated my post, because you updated your post.
I added a new jsfiddle. http://jsfiddle.net/8scyhq01/2/ In general, Input Fields are not draggable, but if you put a layer above the input field, this layer then is draggable. And the Input Field will be dragged too.
$("<div>").addClass("layer").attr("id", "moshe").html("<div class=\"layer\"></div><input readonly type=\"text\"></input>").appendTo("body").draggable();
I have modified
a code I found, From this post to make text input draggable, putting a div on top of it.
$(function() {
$( "#resizable" ).resizable({
containment: "#container"
});
$( "#draggable" ).draggable({containment: "#container"});
});
#container { width: 300px; height: 300px; }
#container h3 { text-align: center; margin: 0; margin-bottom: 10px; }
#resizable, #container { padding: 0.5em; }
#d{
background:blue;
width:100px;
height:30px;
position:relative;
top: 2em;
left:0em;
z-index:9;
opacity:0.1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<div id="container" class="ui-widget-content">
<h3 class="ui-widget-header">Containment</h3>
<span id="draggable"><div id='d'></div>
<input type="text "id="resizable" class="ui-state-active" readonly value="This is input box">
</span>
</div>

In a simple jquery slide show, my class gets to the end of the images and then falls off the edge of the DOM

I'm working on my mobile portfolio (http://lehuagray.com/mobile). Right now a user can flip forward and backward through my images by either sliding or using the buttons. As the user flips, the class .main is removed from their current image and transferred to either the previous or next image. But if the user flips backwards from the first slide or forward from the last slide, .main doesn't have a target to be transferred to. It falls off the edge, and the slide show ceases to function.
The HTML is just a series of divs inside a container. The CSS is probably totally inconsequential except maybe that I had to use z-index to reverse the order of the slide layers (which are absolutely positioned and stacked). Here is a jsfiddle: http://jsfiddle.net/v4b8S/4/. It doesn't matter what the events are, the problem isn't in the events, so I gave the jsfiddle some buttons for ease.
Here is my jQuery code it it's most basic, everything else is just a variation on this:
$( "#rolodexnarrow" ).bind( "swipeleft", function(event) {
$( this ).hide("blind", function() {
$ ( this ).removeClass("main").next().addClass("main")
});
});
$( "#rolodexnarrow" ).bind( "swiperight", function(event) {
$ ( this ).removeClass("main").prev().addClass("main");
$( this ).prev().show("blind");
});
I've tried an if statement:
$( "#rolodexnarrow" ).bind( "swipedown", function(event) {
$( ".main" ).prev().show("blind");
if ( $(".main").is("#slide1") == false ){
$ ( ".main" ).removeClass("main").prev().addClass("main");
}
});
Counter-intuitively (to me at least), this just makes the first and last slides no longer show/hide and no longer receive the .main class, so we get stuck with the second and second-to-last slides up. I have also tried an if statement using (":first"). This is obviously a pretty simple slide show, I'm sure there is a simple solution. I'm sure, also, that this is something that everyone else already knows how to fix but I can't find anything about it since I'm not even really sure what to search for.
Noe: The swipe is a touch interface and barely works on a mouse, especially since everything is linked to lightboxes. If you use a touch device, it doesn't have that problem.
Here you go: http://jsfiddle.net/v4b8S/6/
Here is the updated JS code:
$( ".container" ).bind( "click", function(event) {
if(!$(".main").is("#slide4")) {
$( ".main" ).hide("blind", function() {
$ ( this ).removeClass("main").next().addClass("main");
});
}
});
$(".container").on( "dblclick", function(event) {
if( !$(".main").is("#slide1")) {
$(".main").prev().show("blind");
$(".main").removeClass("main").prev().addClass("main");
}
});
UPDATE1:
Also, read jquery's dblclick event and its handling. In particular, notice that adding handlers for both the click and the dblclick event are not suggested since which one will be triggered first is highly browser and machine dependent. I guess that'll not be a problem for your usecase since you are going to change it to swipe events. (For me, I had to manually trigger the dblclick event using browser console.)
UPDATE2:
The dblclick event handler is also working fine now. I had to change the order of things there.
UPDATE3:
I didn't see your new fiddle till now. Basically it's the same code as above but is activated on the click of the forward and backward buttons.
/*code with if statement, if you want to play with that
$( ".forward" ).bind( "click", function() {
if ( $(".main").is("#slide4") == false ){
$( ".main" ).hide("blind", function() {
$ ( this ).removeClass("main").next().addClass("main")
});
}
});
$( ".backward" ).bind( "click", function() {
$( ".main" ).prev().show("blind");
if ( $(".main").is("#slide1") == false ){
$ ( ".main" ).removeClass("main").prev().addClass("main");
}
});
*/
//simple code
$(".forward").click(function() {
if (!$(".main").is("#slide4")) {
$(".main").hide("blind", function() {
$(this).removeClass("main").next().addClass("main");
});
}
});
$(".backward").click(function() {
if (!$(".main").is("#slide1")) {
$(".main").prev().show("blind");
$(".main").removeClass("main").prev().addClass("main");
}
});
.container {
width: 400px;
height: 400px;
position: relative;
}
.slide {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
#slide1 {
background-color: blue;
z-index: 5;
}
#slide2 {
background-color: green;
z-index: 4;
}
#slide3 {
background-color: yellow;
z-index: 3;
}
#slide4 {
background-color: orange;
z-index: 2;
}
.button {
padding: 14px 7px;
width: 20%;
margin: 20px;
display: inline-block;
background-color: #ccc;
}
.main {
z-index: 10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="slide main" id="slide1"></div>
<div class="slide" id="slide2"></div>
<div class="slide" id="slide3"></div>
<div class="slide" id="slide4"></div>
</div>
<div class="forward button">forward</div>
<div class="backward button">backward</div>

Animating two divs at same time onload, jquery help

I am trying to make a sort of "scales" look, where two divs will slowly animate up and down like being weighed on a scale. I could use some help with the functions though please, I can not get two to animate simultaneously on page load, and I need them to go up, then back down, then up, etc... Make sense? Here is what I have so far, I am kinda new to jquery obviously, :)
Thanks for any help!
<style type='text/css'>
body {
background: #262626;
}
.main
{
margin: 20px auto;
position:relative;
height:400px;
width:300px;
}
.content
{
float: left;
position:absolute;
bottom: 10px;
left: 100px;
height:40px;
width: 100px;
}
.content2
{
float: left;
position:absolute;
top: 10px;
left: 100px;
height:40px;
width: 100px;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
$(document).ready(function() {
$(".content").animate({top:'10px'},{ queue:true, duration:3000 }),
$(".content2").animate({bottom:'10px'},{ queue:true, duration:3000 });
});
</script>
<div class="main">
<div class="content">
<img src="pixel.png" alt="" />
</div>
<div class="content2">
<img src="functional.png" alt="" />
</div>
</div>
If you want them animated simultaneously, you should set queue to false.
document.ready does not wait for images to download. So use window.onload instead. And you should not be queueing if you want them to animate simultaneously. Also, I think in your animation you need to reset the top/bottom values respectively, so they don't interfere with each other...
$(window).load(function() {
$(".content").animate({top:'10px', bottom:0}, 3000);
$(".content2").animate({bottom:'10px', top:0}, 3000);
});
I think there should be a semicolon instead of a comma at the end of this line:
$(".content").animate({top:'10px'},{ queue:true, duration:3000 }),
That would explain why the next line is not being called.
For anyone looking for a solution. The queue: true statement kind of worked, but not really so I created another one.
If you're running the same animation, the best way to execute the command is to put them within one statement.
Use a comma to separate classes/ids.
ie) .content, .content2.
$(document).ready(function() {
$(".content, .content2").animate({top:'10px'},{ duration:3000 }),
done :)
Here is what I came up with, with help from various sources. This give the "teeter totter" effect on page load which I was going for.
<script>$(document).ready(function(){
$("#box1").animate({top:'+=150px'},3000 );
$("#box2").animate({top:'-=150px'},3000 );
$("#box1").animate({top:'-=150px'},3000 );
$("#box2").animate({top:'+=150px'},3000 );
$("#box1").animate({top:'+=100px'},4000 );
$("#box2").animate({top:'-=100px'},4000 );
$("#box1").animate({top:'-=100px'},4000 );
$("#box2").animate({top:'+=100px'},4000 );
$("#box1").animate({top:'+=50px'},5000 );
$("#box2").animate({top:'-=50px'},5000 );
$("#box1").animate({top:'-=20px'},5000 );
$("#box2").animate({top:'+=20px'},5000 );
});
</script>
I'm afraid this may be too "brute force", but I don't know of a better, smoother way to do this.

Categories