How to set the dynamic ids for link? [duplicate] - javascript

This question already has answers here:
How to increment div id value?
(3 answers)
Closed 9 years ago.
I have a horizontal menu. I want to create an id for each using jQuery. My code is:
<div class="menuBar">
<div class="menuHeader ui-corner-top">
<span>Home</span>
</div>
<div class="menuHeader ui-corner-top">
<span>New Transaction</span>
</div>
</div>
Here menu has no id. I want to create id dynamically using jQuery. How can I do this? I did an example like this, but it is not working:
var i = 0;
$('.menuHeader').each(function () {
i++;
newID = menu + i;
$(this).attr('id', newID);
$(this).val(i);
});

The .each() method is designed to make DOM looping constructs concise and less error-prone. When called it iterates over the DOM elements that are part of the jQuery object. Each time the callback runs, it is passed the current loop iteration, beginning from 0.
You have also omitted the quotes when you concatenated menu string with i variable.
$('.menuHeader').each(function (i) {
$(this).find('a').attr('id', 'menu' + (i + 1));
$(this).html((i + 1) + '. ' + $(this).html());
});
jsFiddle Demo

Try this, no need of extra variable i:
$('.menuHeader').each(function () {
$(this).attr('id', 'menu' + ($(this).index() + 1));
$(this).val($(this).index() + 1);
});

Try this
$('.menuHeader').each(function (i) {
newID = "menu_" + i;
$(this).attr('id', newID);
$(this).val(i);
});

Related

The variable is not incrementing properly

I have a webpage that examines users with some questions.
When a person answers one question, it hides and another one comes up.
I came up with a code that uses incrementation but it doesnt work.
I also wrote exactly the same thing just using numbers instead of incrementing variable and it works perfect. What is the difference?
This code works:
$(".questionBox" + 0 + " .answerButton").click(function() {
$(".questionBox" + 0).hide();
$(".questionBox" + 1).show();
$(".answerButton").hide();
});
$(".questionBox" + 1 + " .answerButton").click(function() {
$(".questionBox" + 1).hide();
$(".questionBox" + 2).show();
$(".answerButton").hide();
});
$(".questionBox" + 2 + " .answerButton").click(function() {
$(".questionBox" + 2).hide();
$(".questionBox" + 3).show();
$(".answerButton").hide();
});
But this one NOT:
let i = 0;
$(".questionBox" + i + " .answerButton").click(function() {
$(".questionBox" + i).hide();
i++;
$(".questionBox" + i).show();
$(".answerButton").hide();
});
You do not need to keep track of an index variable. Just declare some indices at data attributes. You can advance to the next question by getting the parent .question-box of the .answer-button and call .next() to go to the next sibling and show it.
$('.question-box').not(':first-child').hide();
$('.answer-button').on('click', function() {
const $parent = $(this.closest('.question-box'));
const index = parseInt($parent.data('index'), 10);
const $next = $parent.hide().next();
if ($next.length !== 0) {
$next.show();
} else {
console.log('Done!');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="questions">
<div class="question-box" data-index="0">
<h2>Question 1</h2>
<button class="answer-button">Answer</button>
</div>
<div class="question-box" data-index="1">
<h2>Question 2</h2>
<button class="answer-button">Answer</button>
</div>
<div class="question-box" data-index="2">
<h2>Question 3</h2>
<button class="answer-button">Answer</button>
</div>
</div>
There are two ways to solve your issue using the incrementing variable, but it's definitely worth thinking in #MrPolywhirls answer above. I'm just adding these to show the issue you are seeing with your compacted code. The first example is to call a method to instantiate the first on, and then as questions get answered you want to instantiate the next ones. That would look something like this:
let i = 0;
function applyToQuestionBox(){
$(".questionBox" + i + " .answerButton").click(function() {
$(".questionBox" + i).hide();
i++;
$(".questionBox" + i).show();
$(".answerButton").hide();
// The answer is given, so initialise the next box (i+1)
applyToQuestionBox();
});
}
// On load, this will be applied to question 0 (or initial 'i')
applyToQuestionBox();
It's a little bit annoying that you call the method again inside there, it means you have to read the flow of your code in chunks and makes it harder to reason about. The second option, though, is having a for loop to simply apply it all on page load, and never worry about it again:
const amountOfQuestions = 10;
for( const i = 0; i < amountOfQuestions; i++ ){
$(".questionBox" + i + " .answerButton").click(function() {
$(".questionBox" + i).hide();
$(".questionBox" + (i + 1)).show();
$(".answerButton").hide();
});
}
This reads rather clearly what's going on there: ten questions, every one of them has a click, and every click has an effect. You can reason about this code.
Hope this clears up the issue you might have been having.
In purer JS (sorry I am more accustomed to it but would advise you to look into that instead of picking up jQuery - pure JS is much simpler now, and jQuery's usefulness is waning every year now). The setup here is to avoid having to predetermine the amount of questions. What if you add one to the HTML, do you want to have to go back to your javascript just to add a question? No, you want to automate this:
// Let's select all question blocks
// It doesn't care if there's two or eight hundred
// It is important to store this in a variable though,
// as we will need to reference this list later to get the
// element after the current one thats displayed.
const questions = document.querySelectorAll( '.question' );
questions.forEach((question, index) => {
// Attach an event listener to the internal button
question.querySelector( 'button' ).addEventListener( 'click', event => {
// Use CSS to hide and display certain elements
question.classList.remove( 'active' );
// Check if the next index exists, if not
// we ran out of elements and have reached the end
if( questions[ index + 1 ] ){
questions[ index + 1 ].classList.add( 'active' );
} else {
alert( 'You completed all questions!' );
}
});
});
.question { display: none; }
.question.active { display: block; }
<section class="question active">
<p>Question 1</p>
<button>Answer</button>
</section>
<section class="question">
<p>Question 2</p>
<button>Answer</button>
</section>
<section class="question">
<p>Question 3</p>
<button>Answer</button>
</section>
I got it solved! The problem was that the selector in the function call is kind of static, it did not increment after the first time in the below code.
let i = 0;
$(".questionBox" + i + " .answerButton").click(function() {
$(".questionBox" + i).hide();
i++;
$(".questionBox" + i).show();
$(".answerButton").hide();
});
It works when i only increment inside of the function:
$(".answerButton").click(function() {
$(".questionBox"+i).hide();
i++;
$(".questionBox"+i).show();
$(".answerButton").hide();
});

Bind function to dynamically created element [duplicate]

This question already has answers here:
Event handler not working on dynamic content [duplicate]
(2 answers)
Event binding on dynamically created elements?
(23 answers)
Closed 7 years ago.
I have some javascript which generates some html elements, like below:
for (var i = 0; i < suggestions.length; i++) {
var suggestion = suggestions[i];
var $li = $('<li data-profile-id="'+ suggestion.id + '" data-profile-name="'+suggestion.first_name + ' ' + suggestion.last_name + ' " class="search-name-result" ></li>');
$suggestionsUl.append($li);
var $img = $('<img src="/img/profile/' + suggestion.picture_url + '" class="search-suggest-img pull-left" />');
$li.append($img);
var $link = $('' + suggestion.first_name + ' ' + suggestion.last_name + '');
$li.append($link);
}
What I need to be able to do is also assign a function to each dynamically created li element, something like the below code:
$('.search-name-result').on('click', function(e){
$input.val($('.search-name-result').data('profile-name'));
});
But im not sure how to assign this to each li when they are created.
Thanks
Almost there, but actually delegate it using a parent container like document
$(document).on('click','.search-name-result', function(e){
$input.val($(this).data('profile-name'));
});
Also, you can change
$('.search-name-result').data('profile-name'))
to use $(this) like
$(this).data('profile-name'))
since it will be the clicked .search-name-result
You should use event delegation for dynamically added elements.
$(document).on('click','.search-name-result', function(e){
$input.val($('.search-name-result').data('profile-name'));
});

Creating several dynamic onclick events in Javascript / Jquery [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
I have an un-ordered HTML list of images. Each Line (li) element has its own id:
<ul id="Demo3">
<li id="li1"><img src="images/FT/HopkinsPrairie.jpg" /></li>
<li id="li2"><img src="images/FT/PineForest.jpg" /></li>
<li id="li3"><img src="images/FT/2011GroupThumb.jpg" /></li>
<li id="li4"><img src="images/FT/JuniperSpringsSwimming.jpg" /></li>
<li id="li5"><img src="images/FT/HappyHourThumb.jpg" /></li>
<li id="li6"><img src="images/FT/HappyHourThumb.jpg" /></li>
</ul>
When I click each image I would like a larger version of the image to appear, sort of like this:
<li id="li2"><img src="images/FT/PineForest.jpg" /></li>
Unfortunately the CSS class associated with #Demo3 does a lot of manipulation to the class associated with all #li elements, so I have to add the anchor in programmatically.
I try doing it like this:
i = 1;
while ($("#li" + i).length > 0) { // If the li id exists
myLink = "images/FT/Page" + i + ".jpg"; // create a link
var element = document.getElementById("li" + i); // get the element
element.onclick = function () { // create an onclick for this element
var win = window.open(myLink, '_blank');
win.focus();
}
i++;
}
This does not work! For whatever reason, each image gets the same onclick as the last one in the list.
Does anyone know what I'm doing wrong or how to solve this so that each image contained within each li element gets its own onclick?
Any other suggestions?
Another Approach, Use Wildcard selectors:
$("[id^=li").each(function(index, value) {
value.click(function () {
var id = parseInt(value.id.substring(2)); // strip "li", convert to int.
var win = window.open("images/FT/Page" + id + ".jpg", '_blank');
win.focus();
});
});
or simply
$("[id^=li").click(function (event) {
var id = parseInt(this.id.substring(2)); // strip "li", convert to int.
var win = window.open("images/FT/Page" + id + ".jpg", '_blank');
win.focus();
});
This does not work! For whatever reason, each image gets the same onclick as the last one in the list.
The direct solution for you is this:
while ($("#li" + i).length > 0) { // If the li id exists
(function(i) { // <---- THIS LINE
var myLink = "images/FT/Page" + i + ".jpg"; // create a link
var element = document.getElementById("li" + i); // get the element
element.onclick = function () { // create an onclick for this element
var win = window.open(myLink, '_blank');
win.focus();
}
i++;
})(i); // <---- and THIS LINE
}
The reason is, myLink was being captured in your onclick closure. Your loop went a number of times, each time changing myLink and creating a closure on myLink. When the onclick triggered, the myLink value is the last value it had at the end of the loop - not at the time the closure was created.
The approach above, using an IIFE, "fixes" the value of i, and creates a separate variable myLink in each iteration for the onclick handler to close over.
The alternative approach by OneWay does this by directly using another closure as the callback of each. I'd use his solution in your code, and this answer to help you understand why your original behaved as it did.

Multiple buttons with the same ID [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
SOLVED: Not enough coffee - the event listener was being added before the buttons were created.
Im creating a table from HTML LocalStorage like so:
for (i = 1; i <= localStorage['count']; i++) {
tableHtml = tableHtml + "<tr><td><button class='delete' id=" + i + ">Delete</button></td><td>" + localStorage['fullName' + i] + "</td><td>" + localStorage['email' + i] + "</td><td>" + localStorage['phoneNum' + i] + "</td></tr>";
}
This works great, however the delete button is proving troublesome.
I saw this:
jQuery find ID of clicked button by class
So I assumed i could do this:
$(".delete").click(function () {
alert('delete clicked for id: ' + $(this).id);
});
However, it doesn't work. Suggestions?
you can get the id of element by using javascript without using jquery wrapper like this:
$(".delete").click(function () {
alert('delete clicked for id: ' + this.id); // get id via javascript
});
or:
$(".delete").click(function () {
alert('delete clicked for id: ' + $(this)[0].id); // via javascript object
});
If you see the link reffered in question it is also getting id using javascript (this.id)
if you want to get via jquery then:
$(".delete").click(function () {
alert('delete clicked for id: ' + $(this).attr("id")); // via jquery object
});
When are you binding the click event? If it's before the element exists, you'll want to use .on.
$('body').on('click','.delete', function(){
alert('delete clicked for id: ' + $(this).attr('id'));
});
Check out a working jsFiddle.
use pure javascript:
this.id
or jquery
$(this).attr('id');
as $(this) is jquery object. and you are trying to get javascript property id. You need to first convert the object to javascript.
$(this)[0].id;
DOM elements shouldn't have numbers as the first character of id.
Change your code to something like this:
for (i = 1; i <= localStorage['count']; i++) {
tableHtml = tableHtml + "<tr><td><button class='delete' id=del-id" + i + ">Delete</button> </td><td>" + localStorage['fullName' + i] + "</td><td>" + localStorage['email' + i] + "</td><td>" + localStorage['phoneNum' + i] + "</td></tr>";
}
And
$(".delete").click(function () {
alert('delete clicked for id: ' + $(this).prop('id');
});
This should take you on the right track.
REMEMBER that .prop() function is jQuery 1.10+ specific.
If you are using an older version use .attr()
As some people here mentioned - id's can be numeric as of HTML5
still using them in a numeric form might generate rather unpleasant problems.
Link in the comments below from one of the users.

Select items with a class and tagname [duplicate]

This question already has answers here:
How to Get Element By Class in JavaScript?
(12 answers)
Closed 8 years ago.
I want to use JS to find all items with an A tag, and the class Titanic. How would i go about this without querySelector. I want the method to be fast. So preferably no loops.
You won't get away from loops.
You can use the document.links collection that already contain all the links in the page, and check the class name of each:
var el = [];
for (var i = 0; i < document.links.length; i++) {
if (document.links[i].className == 'Titanic') {
el.push(document.links[i]);
}
}
Demo: http://jsfiddle.net/TrhCG/
Note: The links collection only contains actual links, i.e. anchor tags (and area tags) with a href attribute. Also, the way to compare the class name only works if the element contains only that class name.
You can use getElementsByTagName() function to select anchor tags. You can check the classname using .classname property.
var elems = document.getElementsByTagName('*'), i;
for (i in elems) {
if((' ' + elems[i].className + ' ').indexOf(' ' + matchClass + ' ')
> -1) {
/*Do something.*/
}
}
Life's much easier if you use jQuery though.

Categories