Creating unique IDs with JQuery - javascript

This question is prob a duplicate (but I can't find it) so I apologize if it's redundant. I am trying to use JQuery's .remove function to allow for removing (obviously) of li elements in my static HTML prototype. Rather than write out a javascript block for each li I want to remove I was wondering if it was possible to create incrementing IDs with JS alone. (I'm using Serve with HAML and SASS fyi). Here is what I have.
/view-file.html.haml
%ul
%li#removeThis1
%a.remover1{:src => "#"} Remove
/application.js
...
$(".remover1").click(function () {
$("li#removeThis1").fadeOut( function() { $(this).remove(); });
});
Any thoughts on how to increment .remover1 to .remover2, etc? Likewise li##removeThis1 to #removeThis2, etc.
I would need all this to happen on page load.

There's an ancestral relationship between the elements, so just use that to your advantage.
// don't bother numbering the class. Use a common class
$(".remover").click(function () {
// find the closest ancestor with an ID that start with "removeThis"
$(this).closest("li[id^=removeThis]")
.fadeOut( function() { $(this).remove(); });
});
Or if you don't really need an ID on the ancestor, use a class there too...
// don't bother numbering the class. Use a common class
$(".remover").click(function () {
// find the closest ancestor with the class "removeThis"
$(this).closest(".removeThis")
.fadeOut( function() { $(this).remove(); });
});
Ultimately, if you were to use IDs, you'd want to generate them on the server side, then extract the numeric portion of the ID from the element with the handler, and concatenate it into the selector for the ancestor.

Related

Create new element from selector?

How can I create a new element using just a selector? (e.g. .myclass, #myid or a:not(.someclass)) Basically there is no way for you to tell if the element is a div, span, li, an anchor, if it's a div with a class or with an id and so on.
In jQuery I know you can do $(selector) to get a usable DOM object. But how can this be done in JavaScript?
In jQuery I know you can do $(selector) to get a usable DOM object...
Not to create one. jQuery will do a search in the DOM for existing matches. You can do $("<div>") and such (note that's HTML, not a CSS selector) to create elements, but jQuery doesn't have a feature for creating elements from CSS selectors.
But how can this be done in JavaScript?
You'll have to parse the selector, and then use document.createElement with the tag name, and then set any classes or other things the selector describes on the new element.
CSS selectors aren't very hard to parse. You'll be able to find a lib that does it. (jQuery has Sizzle, which is a selector engine, built in and Sizzle is open source. It will naturally have code to parse selectors.)
Mootools does this.
new Element('#name.class')
yields
<div id=​"name" class=​"class">​</div>​
The answer appears to be that there is no built-in way of doing this. Maybe there’s a library which does the job.
However, it’s not to hard to write a function to create an element from a simple selector:
/* createElementFromSelector(selector)
================================================
Usage: element#id.class#attribute=value
================================================ */
function createElementFromSelector(selector) {
var pattern = /^(.*?)(?:#(.*?))?(?:\.(.*?))?(?:#(.*?)(?:=(.*?))?)?$/;
var matches = selector.match(pattern);
var element = document.createElement(matches[1]||'div');
if(matches[2]) element.id = matches[2];
if(matches[3]) element.className = matches[3];
if(matches[4]) element.setAttribute(matches[4],matches[5]||'');
return element;
}
var testitems = [
'div#id.class#attribute=value',
'div#id.class#attribute',
'div',
'div#id',
'div.class',
'#id',
'.class',
'#id.class',
'#whatever'
];
testitems.forEach(item => {
var element = createElementFromSelector(item);
console.log(element);
});
The tricky part is the regular expression. You can see it in detail here: https://regex101.com/r/ASREb0/1 .
The function only accepts selectors in the form element#id.class#attribute=value with the any of components being optional, as you see in the test items. I think including pseudo classes is probably pushing the friendship, but you might like to modify it to include multiple real classes.

Creating a "selected item" javascript code for navigation menu?

I have a navigation menu with about 10 items, and I put together this code to update the links for which is selected and which is not. It manually updates classes. The problem is, as you can probably tell, its inefficient and its a pain to update. Is there a better way of doing it?
$('#Button1').click(function(){
$('#Button1').addClass("selectedItem");
$('#Button2').removeClass("selectedItem");
$('#Button3').removeClass("selectedItem");
$('#Button4').removeClass("selectedItem");
$('#Button5').removeClass("selectedItem");
$('#Button6').removeClass("selectedItem");
$('#Button7').removeClass("selectedItem");
$('#Button8').removeClass("selectedItem");
$('#Button9').removeClass("selectedItem");
$('#Button10').removeClass("selectedItem");
});
You could try something like this -
$("[id^='Button']").removeClass("selectedItem");
$('#Button1').addClass("selectedItem");
This will first remove all the selectedItem classes from any element which has an id attribute starting with "button". The second command then adds the class to Button1
You could also simply bind all the elements with the same handler like this -
var $buttons = $("[id^='Button']");
$buttons.on('click', function ()
{
$buttons.removeClass("selectedItem");
$(this).addClass("selectedItem");
});
For each element, when clicked, the class will be removed - the element that was clicked with then have the class added.
Checkout the Attribute Starts With Selector [name^="value"] selector.
I would suggest using classes because this is exactly what they are for - to denote groups of elements. While you can easily select your buttons using the method proposed by Lix (and you should use this method if you can't modify HTML), using class is a more unobtrusive:
var $buttons = $('.button').on('click', function() {
$buttons.removeClass('selectedItem');
$(this).addClass('selectedItem');
});
Meta example: http://jsfiddle.net/88JR2/
You could have a class .button and apply it to all your buttons then
$('#Button1').click(function(){
$('.button').removeClass("selectedItem");
$('#Button1').addClass("selectedItem");
});

jQuery Design Pattern for Updating Selectors When the HTML Changes

I'm looking for some advice on a making my jQuery selectors more configurable. For example, given the following HTML generated by PHP:
<ul id="my-list">
<li>first</li>
<li>second</li>
</ul>
And a bit of jQuery:
$(function() {
$(document).on("click", "#my-list li", function() {
alert("You clicked " + $(this).text());
});
});
So far so good, but then one day the designer comes along and renames the id "my-list" to "list-of-numbers", and the javascript stops working. Currently the solution is remembering to grep through the code for any references to "my-list", but that's very faulty. Is there a jQuery design pattern for making the selectors configurable?
This can be called 'selector selection.' You can define a set of variables that have the selectors in them as a solution:
var selectors = { myLi: "#my-list li",
myUl: "#my-div ul" };
Then you can simply do an object lookup to get the selector:
$(selectors.myLi);
This has the advantage of being readable and dynamic; however, in your example scenario where someone changes the ID, this would not be very helpful unless it's explicitly noted somewhere in your code that changes are necessary.
You might want to consider doing some delegation and using custom data attributes to define roles.
Define a set of selectors at the beginning of your JS-Code (don't forget to add a comment for what you use it):
var selectors = {
'listSelector':'#my-list li' /* DESC */,
'nextSelector': '.whatever'
}
and use them in your queries:
$(document).on("click", selectors.listSelector, function() {
alert("You clicked " + $(this).text());
});

How can I use multiple Floating Help Dialogue by using 'class' instead of 'id'?

I need to use multiple floating help dialog boxes in a page. I have tried it by using 'display:block' and 'display:none' and used ID in javascript. I cannot use classes since I have multiple of them on the same page and if I use classes then all of them will be displayed/hide at the same time. However, as the number of help items are increasing in the page, I have to go back to the javascript and add more lines ...
for example:
$(document).ready(function() {
$("#help-icon1").click(function() {
$('#help-details1').css('display', 'block');
});
$("#help-icon2").click(function() {
$('#help-details2').css('display', 'block');
});
$("#help-icon3").click(function() {
$('#help-details3').css('display', 'block');
});
});
Each of them also have close icons and they should be disappeared if clicked on that close icon or clicked anywhere in the page. That means I have to write javascript functions 3 times for all the different close icons.
I tried to rely on jquery's "next" feature, but since there are many layers (div/p/span) in between the areas where the help icon is places and the help text, it becomes problamatic. Any idea or any better way to resolve this?
Thanks in advance.
I'm not quite sure I understand what you are looking for, but you can set up all the click handlers in one step, and have each one refer to itself in the handler:
jQuery(".help-icon").click(function() {
jQuery(this).css('display', 'block');
});
You can add additional class names to an element.
A div can be hidden by default, and a new class can be appended to it - to "overrule" the previous style (Hence the name Cascading Style Sheets)
<div class="hidden exception"></div>
If an element is clicked, you can append a new classname like so:
$('.target').addClass('newclass');
more info:
http://api.jquery.com/addClass/
I've not done it using JQuery but what you need is "unobtrusive javascript".
It does get done by using a class. Say you have images you all want highlighted:
<img src="pic1.png" onMouseover="this.src='hi_pic1.png';" />
so they all have the same behaviour. Give them a class:
<img src="pic1.png" class="hi" />
Then at load time, on in the script at the end of your page, yahoo-style, you write an initialisation to
- grab every element of the class
- add the event(s) you want
- set the event to use the appropriate data, e.g. by using this and by using systematic names like pic1 -> hi_pic1.
Hope this helps,
Charles
Have you tried the jQuery .each function?
EDIT: Like the following
$(".help-icon").each(function(idx, elm){
elm.click(function(){
...
})
});
If all of your help icons have the same class you can use jQuery's each function to loop through them, retrieve the associated id, replace "icon" with "detail" in the id (so #help-icon3 would become #help-detail3), and then use that to update the panel. Something like:
$(".help-icon").each(function() {
var detailsId = $(this).attr("id").replace("icon", "details");
$("#" + detailsId).css('display', 'block');
});
Let's just ASSUME that you need to use IDs for some unknown reason. Here's your answer to combine efforts:
$("#help-icon1").add("#help-icon2").add("#help-icon3").click(function() {
$(this).css('display', 'block');
});
Which equates to:
$("#help-icon1, #help-icon2, #help-icon3").click(function() {
$(this).css('display', 'block');
});
But really, you don't need to use unique IDs like this without some pretty good reasons.

Selecting only one element in the jQuery collection

How do I limit an event to a single element in a jQuery collection?
In the case below, I've tried using .one() to limit the behaviour (inserting the <li class='close'>Close</li> line of HTML) to a single instance. The behaviour does indeed happen only once, but on EVERY matched element of $( "ul>li>a" ). How do I make it happen only once, to only ONE of the matched elements in the collection?
Any ideas?
$( "ul>li>a" ).one(
"click",
function(){
$( "ul ul")
.prepend("<li class='close'>Close</li>")
}
);
Thanks in advance.
-AS
A jQuery selection returns an array. Therefore $("selection")[0] can work. However there are better abstracted methods for this, like .get(0) or .first() (in case you're looking for the first element of the selection/array).
$("selection").get(index) returns the pure DOM element (at that specific index) of the selection, and is not wrapped in the jQuery object.
$("selection").first() returns the first element of the selection, and wraps it in a jQuery object.
So if you don't necessarely want to return the first element, but still want jQuery functionality, you can do $($("selection").get(index)).
Given your situation, this should work fine:
// bind the 'onclick' event only on the first element of the selection
$( "ul>li>a" ).first().click(function() {
$( "ul ul").prepend("<li class='close'>Close</li>");
});
Which is equivalent to this:
$($( "ul>li>a" ).get(0)).click(function() {
$( "ul ul").prepend("<li class='close'>Close</li>");
});
And this:
$($( "ul>li>a" )[0]).click(function() {
$( "ul ul").prepend("<li class='close'>Close</li>");
});
I must disagree with Ryan, working on the CSS selection string to filter the result is rather expensive compared to the native JavaScript array functionality.
Try first(), it selects the first element:
$( "ul>li>a" ).first().one('click',
function(){
$( "ul ul").prepend("<li class='close'>Close</li>")
}
);
one() is used, as you already noticed, to handle an event only once.
You have to specify the index of the element you want to work with.
If your selector returns more than one element you can do one of a couple things...
You can isolate your elements by giving them a class or id attribute in your html and alter the selector to select only the class/id of the element/s you wish to select or you can specify the index of the element you're trying to work with. The later method is a bit sloppy but works as long as your page structure doesn't ever change.
So for the first method I spoke of you'd change your selector to this after applying a class/id to your elements:
$("ul>li>a.class")
or
$("ul>li>a#id")
For the second method I mentioned you'd change your selector to this:
$("ul>li>a:eq(index)")
Where index is the zero based index of the element you're trying to select.
You can call the first method, which will return a new jQuery object containing only the first element in the original one.
However, in your case, you might as well use the (equivalent) :first selector, like this:
$("ul > li > a:first").click(function() { ... });
If you only want to handle the first click event and ignore any subsequent clicks, you'll need to use .one(), like you already are.
You need to combine first() with one():
$( "ul>li>a" ).first().one('click', function () {});
More general:
$( "ul>li>a:eq(n)" ).one('click', function () {});

Categories