while loop in Javascript with concatenation - javascript

I'm trying to make a while-loop in my Javascript.
So far, I've got this:
<script>
$(document).ready(function(){
var i=0;
while (i<9999) {
$(".add_new_item_field" + i).hide();
$(".add_new_item_button" + i).click(function(){
$(".add_new_item_field" + i).slideToggle("slow");
});
i++;
}
});
</script>
Goal is to make this work:
<div class="add_new_item_button1"></div>
<div class="add_new_item_button2"></div>
<div class="add_new_item_button3"></div>
...
<div class="add_new_item_field1">Show me something</div>
<div class="add_new_item_field2">Show me something</div>
<div class="add_new_item_field3">Show me something</div>
...
But for some reason, it's not working. Am I missing something here?

Your problem is that the concatenation in the line $(".add_new_item_field" + i).slideToggle("slow"); happens when you click one of the divs. Yet, the loop that had set up the handlers was run long ago then and i already has a value of 9999. Use a closure as #David demonstrated to avoid this.
However, I feel this is the wrong approach. Setting up 10000 click handlers, and executing 20000 jQuery selection does make your page very, very slow. Use one common class for the button, and one common class for the fields. If you can't depend on a certain document order, give them unique ids to refer to each other - but not classes.
Then hide all the fields with one single line of CSS, and use event delegation for the buttons to fire 1 single function that looks up the field by id from the data attached to the clicked button.
<style>
.add_new_item_field { display:none; }
</style>
<!-- placing the stylesheet here also avoids flickering.
Even better would be of course if it was written dynamically by JS, for not
hiding the fields in clients that do not support JavaScript -->
<script src=/"jquery.js"></script>
<script>
jQuery(function($) {
$(document).on("click", ".add_new_item_button", function(e) {
var id = "field"+$(this).data("field");
$('#'+id).show();
});
});
</script>
<div class="add_new_item_button" data-field="1"></div>
<div class="add_new_item_button" data-field="2"></div>
<div class="add_new_item_button" data-field="3"></div>
...
<div class="add_new_item_field" id="field1">Show me something</div>
<div class="add_new_item_field" id="field2">Show me something</div>
<div class="add_new_item_field" id="field3">Show me something</div>
...

I’m guessing that i is not what you expect it to be in the handler, because when the handler executes i has already maxed out to 9999. To fix that, you need to bring the variable into the handler closure, something like:
var i=0;
while (i<9999) {
$(".add_new_item_field" + i).hide();
$(".add_new_item_button" + i).click((function(i) {
// i is now saved in this closure
return function() {
$(".add_new_item_field" + i).slideToggle("slow");
};
}(i)));
i++;
}
Sidenote: I’m not really sure this is the best way to solve your actual task here though, looping and attaching 9999 event handlers seems unnecessary...

I think you are using the class the wrong way. You can assign a click handler to all objects of the same class. But you are trying to use the class specifier as an ID and are trying to assign the handler to each seperate object. You wouldn't do the same for the behavior and layout of a link/url? (link) would you?
Read this: jQuery: How do I add a click handler to a class and find out which element was clicked?
You want to setup the handler for a class, specify your divs as that class. I not abusing the class specifier as some sort of ID.

You are creating a closure in your click handler which captures the i variable, not it's value. This means all the click functions will contain the value 9999 which the value of the variable at the end of the while loop.
You can fix it by creating a function that set's the click handler.
var setClick = function(index) {
$(".add_new_item_button" + index).click(function(){
$(".add_new_item_field" + index).slideToggle("slow");
}
}
And use it in your while loop.
while (i<9999) {
$(".add_new_item_field" + i).hide();
setClick(i);
i++;
}
Now the value of i is correctly captured by your click handler

Related

moving inline js to a seperate file

I have onmouseover and onclick in my html and I would like to move them to separate js file (in js folder).
with onmouseover i do try however i can't make it work. it is supposed to be changing (just once) from img/cacti-edit.jpg to img/cacti.jpeg.
my html :
<div class="pic">
<img src="img/cacti-edit.jpg" alt="close-up of a cactus and its spikes"/>
</div>
my js:
let picture = document.getElementsByClassName("pic");
picture.addEventListener("mouseover", function( event ) { picture.src='img/cacti.jpeg'; }, false);
console.log(picture)
log is : TypeError: picture.addEventListener is not a function.
HTML:
<ul>
<li onclick="swapStyleSheet('css/fixed.css')">Fixed width</li>
<li onclick="swapStyleSheet('css/responsive.css')">Responsive</li>
</ul>
and in JS I have:
function swapStyleSheet(sheet) { document.getElementById("pagestyle").setAttribute("href", sheet); }
and I dont know at all how to move this onclicks into seperate js.
Thanks
Your issue is not with the file, as you have shown you are getting an error from the event listener.
The reason is because getElementsByClassName() returns an array. You cannot assign a listener directly to an array. You need to access an element in the array and assign the listener to that.
let picture = document.getElementsByClassName("pic");
picture[0].addEventListener("mouseover", function( event ) {
picture.src='img/cacti.jpeg'; }, false);
Next, to add it to a separate file, simply add those functions to a file and import the file into your html.
For example:
Filename: test.js
Import line:
<script src="test.js" type="text/javascript">
The document.getElementsByClassName() selector will return an array, even if you have just one element to fit that query. You are trying to add an EventListener in a array, wich is impossible. 2 possible solutions are:
Using a for loop in case you have more than 1 element with pic class:
let picture = document.getElementsByClassName("pic");
for(let pictureEl of picture) //You can use any loop that you find most convenient
pictureEl.addEventListener("mouseover", function( event ) { pictureEl.src='img/cacti.jpeg'; }, false);
Select the array first element. This way you'll work with that specific div. Just add something in your query.
let picture = document.getElementsByClassName("pic")[0]; /*Since we are dealing with an array, index 0 represents its first element*/
This should solve your problem. Comment if you need any clarification.

Drawing 3D objects

I'm looking to draw a 3D cylinder with javascript by copying the layers and applying an increased margin to these elements. I have tried to set the height of the element in my input and run the copy function while total margin of the copied elements is lower than the set height of elements.
http://jsfiddle.net/yuX7Y/3/
<form>
<input type="number" id="userHeight" />
<button type="submit" onclick="circleHeight">Submit</button>
</form>
<div class="circle">
</div>
<div class="slice">
</div>
$(document).ready(function(){
var initMargin = 4;
var totalMargin = 0;
var i = 0;
function copy(){
$(".slice").clone().appendTo( ".content" ).css({'margin-top': totalMargin + "px"});
console.log("cloned");
i++;
totalMargin = initMargin + 4;
}
function setH(){
while(i < (document.getElementById("userHeight").value)){
copy();
}
if(i>100){
initMargin = 4;
i=0;
}
}
});
Jump To The Result: http://jsfiddle.net/yuX7Y/15/
Notes
This Fiddle/question intrigued me so I went ahead and looked at it for a little while. There were actually a number of issues, some obvious and some less obvious. Somewhat in the order I noticed them these are some of the issues:
jQuery wasn't included in the fiddle
The click event wasn't wired up correctly - it was actually trying to submit the form. You need to use e.preventDefault to stop the form from submitting. Since you were already using jQuery I just wired up with the jQuery click event:
$("#recalculateHeight").click(function (e) {
e.preventDefault();
setH();
});
Because of the use of "global" variables (variables not initialized within the routines), the submit would only work once. Instead of this, I moved variable declarations to the appropriate routine.
Calling $(".slice").clone() clones ALL slice elements on the page. The first time you clone, this is fine. But after that you are cloning two elements, then three elements, etc (as many slice elements as are on the page). To solve this I created a slice template like:
<div class="slice" id="slice-template" style="display: none"></div>
Then you can clone to your hearts content like $("#slice-template").clone(). Just don't forget to call the jQuery show() method or set display back to block on the cloned element.
Finally, if you want to repeat the process many times you need to be able to clear previous elements from the page. I find this easiest to do by creating containers, then clearing the contents of the container. So I put all of the "slices" into this container:
<div class="content">
Now when you want to clear the content node you can just call $(".content").empty();.
I also made a few style based changes in my Fiddle, but those don't make it work or not work, they just help me read the code! So, there you have it! Best of luck!

How do I make an OnClick function that will change a word when a user clicks it to another word?

Okay so, I want to make an OnClick function in JavaScript that makes it so when a user clicks on it, it will change the word. Is there a replaceword() function or something that which will let me do so? I know this is not real code, but for example:
<p>Quickly <span onclick="replaceword('Surf');">Search</span> The Web!</p>
If there is, then can someone tell me also how to reverse the code maybe? So when they click on it the second time, it will change back to "Search"?
If you want to jump between multiple words, you'll need to store them someplace. You could have two words in the sentence, and toggle the visibility of one or the other (which doesn't scale well), or you could even store them as values on an attribute placed on the element itself.
<p>Hello, <span data-values="World,People,Stack Overflow">World</span>.</p>
I have placed all possible values within the data-values attribute. Each distinct value is separated from the other values by a comma. We'll use this for creating an array of values next:
// Leverage event-delegation via bubbling
document.addEventListener( "click", function toggleWords ( event ) {
// A few variables to help us track important values/references
var target = event.target, values = [], placed;
// If the clicked element has multiple values
if ( target.hasAttribute( "data-values" ) ) {
// Split those values out into an array
values = target.getAttribute( "data-values" ).split( "," );
// Find the location of its current value in the array
// IE9+ (Older versions supported by polyfill: http://goo.gl/uZslmo)
placed = values.indexOf( target.textContent );
// Set its text to be the next value in the array
target.textContent = values[ ++placed % values.length ];
}
});
The results:
The above listens for clicks on the document. There are numerous reasons why this is a good option:
You don't need to wait for the document to finish loading to run this code
This code will work for any elements added asynchronously later in the page life
Rather than setting up one handler for each element, we have one handler for all.
There are some caveats; you may run into a case where the click is prevented from propagating up past a particular parent element. In that case, you would want to add the eventListener closer to your target region, so the likeliness that bubbling will be prevented is less.
There are other benefits to this code as well:
Logic is separated from markup
Scale to any number of values without adjusting your JavaScript
A demo is available for your review online: http://jsfiddle.net/7N5K5/2/
No, there isn't any native function, but you can create on your own.
function replaceword(that, word, oword) {
that.textContent = that.textContent == oword ? word : oword;
}
You can call it like this:
<p>Quickly<span onclick="replaceword(this,'Surf','Search');">Search</span>The Web!</p>
Live Demo: http://jsfiddle.net/t6bvA/6
<p id="abc">Hello</p>
<input type="submit" name="Change" onclick="change()">
function change(){
var ab=document.getElementById('abc').value;
ab.innerHTML="Hi, Bye";
}
I think so this should help you, you should go to site such as w3schools.com, its basic and it will answer your doubt
You can try something like this if you wanna use jQuery
http://jsfiddle.net/R3Ume/2/
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<body>
<p>Hello <a id='name'>John<a></p>
<input id="clickMe" type="button" value="replace" onclick="onClick();" />
<script>
function onClick() {
$('#name').text('world');
}
</script>

How can I append dynamic variables to div with jquery?

I'm having some difficulty getting this to work. What I want to do is take dynamic variables from the onclick and place them into a div I am appending to another div in the document. Since each each item will have variables associated from a database query, I figured populating the buildTicket() variables from the database would be easier.
I know I'm doing something wrong. I just can't figure out what.
If you have a better way, I'm all ears.
Here is my javascript:
<script type="text/javascript">
$(document).ready(function(){
$(function() {
buildTicket = function(eventname,ticketprice,venueid,userid) {
$(".ticketbtn").click(function(){
$(".ticketwindow").append("<div class='ticket'>" + eventname + " - " + eventprice + "</div>");
});
}
});
</script>
Here is my HTML:
<div class="ticketbtn" onclick="buildTicket('Some Show','12.00','1','2');">
<img src="assets/images/tixicon.png" alt=""> <div class="eventname">Some Show</div>
<div class="ticketprice">Adult - 12.00 </div>
</div>
<div id="ticketwindow">
</div>
Can someone help me figure this out?
(sorry for the code formatting. Still trying to figure out how to use stackoverflow's forms properly.)
Thanks,
Joe
Firstly, $(function() { is equivalent to $(document).ready(function() { so you only need one of them.
Secondly, you don't need to use the onclick attribute if you are binding to click() with jQuery, or vice versa.
If you just use the onclick attribute, then you can remove your document ready handler, and your click() binding, all together and simply define the buildTicket() function.
Thirdly, the eventprice variable is misnamed in buildTicket().
Here is a working fiddle, using jQuery to bind to the click event of your button div. http://jsfiddle.net/BdJAL/
You are binding the onClick listener on click of your button.
If you must use the onClick element attribute then the following code will work although you should become familiar with the principles of Unobtrusive JavaScript.
$(document).ready(function(){
var buildTicket = function(eventname,ticketprice,venueid,userid) {
$("#ticketwindow").append("<div class='ticket'>" + eventname + " - " + eventprice + "</div>");
});
});
I quote from your question:
"I figured populating the buildTicket() variables from the database would be easier."
If you want to get hold of database data in your JavaScript how about making an HTTP request to get it. Obviously, you could do this in the normal XJAX way using XMLHttpRequest:
http://www.w3schools.com/xml/xml_http.asp
Or you could call up some server side code to produce JSON for you and reference it in a <script> tag e.g.
<script type="text/javascript" src="../js/jsonFromServerSideCode.jsp"></script>

JQuery Copy text & paste into textarea

I've created a javascript function that will take a hidden span, copy the text within that span and insert it into a single textarea tag on a website. I've written a function in JavaScript that does this (well, kinda, only after a few clicks), but I know there's a better way - any thoughts? The behavior is similar to a Retweet for twitter, but using sections of a post on a blog instead. Oh, and I'm also calling out to jquery in the header.
<script type="text/javascript">
function repost_submit(postID) {
$("#repost-" + postID).click(function(){
$("#cat_post_box").empty();
var str = $("span#repost_msg-" + postID).text();
$("#cat_post_box").text(str);
});
}
</script>
Based on the comment in your question, I am assuming you have something like this in your HTML:
copy post
And I am also assuming that because you are passing a post ID there can be more than one per page.
Part of the beauty of jQuery is that you can do really cool stuff to sets of elements without having to use inline Javascript events. These are considered a bad practice nowadays, as it is best to separate Javascript from your presentation code.
The proper way, then, would be to do something like this:
<a href="#" id='copy-5' class='copy_link'>copy post</a>
And then you can have many more that look similar:
<a href="#" id='copy-5' class='copy_link'>copy post</a>
<a href="#" id='copy-6' class='copy_link'>copy post</a>
<a href="#" id='copy-7' class='copy_link'>copy post</a>
Finally, you can write code with jQuery to do something like this:
$(function() { // wait for the DOM to be ready
$('a.copy_link').click(function() { // whenever a copy link is clicked...
var id = this.id.split('-').pop(); // get the id of the post
var str = $('#repost_msg-' + id); // span not required, since it is an ID lookup
$('#cat_post_box').val(str); // empty not required, and val() is the proper way to change the value of an input element (even textareas)
return false;
});
});
This is the best way to do it even if there is only one post in the page. Part of the problem with your code is that on the first click it BINDS the function, and in the subsequent clicks is when it finally gets called. You could go for a quick and dirty fix by changing that around to just be in document.ready.
$("#repost-" + postID).click(function(){
$("#cat_post_box").val(''); // Instead of empty() - because empty remove all children from a element.
$("#cat_post_box").text($("#repost_msg-" + postID).text());//span isn't required because you have and id. so the selector is as efficient as it can be.
});
And wrap everything in a $(document).ready(function(){ /Insert the code here/ }) so that it will bind to $("#repost-" + postID) button or link when the DOM is loaded.
I had a problem with Paolo's example when I clicked on the link the text that appeared in #cat_post_box was "object Object". Once I added ".text()" to the end of that statement I worked.
var str = $('#repost_msg-' + id).text();
Thanks for you example Paolo!

Categories