Duplicating IDs Jquery - javascript

So, I have done some research, and it's pretty clear that id should be unique in the DOM. This is my issue, and I am curious what the best solution to it is:
I am using jQueryUI tabs as well as a custom menu and ajax to load specific pages into a content pane without re-rendering the browser. From some of these sub pages, a user can open a popup (done with a jQueryUI dialog) to edit customer information. Because these load a server side page, in each place that this form would be generated, it uses the same ids.
I have found that there are a number of ways to close a dialog without removing it from the DOM. This causes confusion later when it, or another form is opened elsewhere, and now there are conflicting ids present in the DOM. I am working on tracking down all the ways to close a dialog, and making sure to replace them with .dailog("destroy").remove() to make sure that they are erased from the DOM, but I want to be sure the solution here is fool proof in the event that someone one gets left on the page.
My two immediate thoughts:
1.) Generate a random string to append to each form element's id when the form is rendered, fully preserving uniqueness of the id.
2.) Use more specified selectors when getting the form data, i.e. scoping it to the popup that was created, the page that it was created from, and then the tab that it is under, and not worrying as much about id uniqueness.
The first feels ugly, and in theory you COULD randomly duplicate the string and still run into an issue. The later just feels bulky and ugly to me. Is there an option I am missing? What is best practice when it comes to dealing with IDs that can be duplicated in this way?
Thanks,
Eric

You may use classes if you need "similar" objects. Id's purpose is to identify object uniquely.
By the way, classes are widely used, for example, in Bootstrap.
UPDATE: I think your "second" approach is bad, as you eventually can change the layout, but, in this way, you should track every change, and remember WHERE to change your selectors (possibly, it will be multiple places).

Before inserting the new element into the list, you could check if there is already an element existing on the page with that id. If it does exist than delete it.
Like:
if($("#"+your_id).length!==0)
$("#"+your_id).remove();
//insert the new element
But if you need that element as well, i would suggest that you use classes to group elements used for same purposes.

Here is what you can do to distinguish between the different dialogs when you try to close them:
1) Change each dialog id into a class, so that your dialogs can share the same class. Using the same id is not recommended.
2) You can create a click listener for the button that closes the correct dialog by using the event callback parameter. See the working snippet below.
var closeButtons, i, closeButtonsLen;
closeButtons = document.getElementsByClassName('close');
for (i = 0, closeButtonsLen = closeButtons.length; i < closeButtonsLen; i += 1) {
closeButtons[i].addEventListener('click', function (e) {
e.target.parentNode.setAttribute('hidden', true); // if you want to hide the dialog
});
}
<div class="dialog"><button class="close">first x</button></div>
<div class="dialog"><button class="close">second x</button></div>
<div class="dialog"><button class="close">third x</button></div>
You can replace e.target.parentNode.setAttribute('hidden', true); with whatever you need to do. e.target.parentNode gets the dialog element.

Related

How can I add a disable class to a single select, not all of that I have

I want to put a disabled class into my select, but when I do this:
$("input").attr("disabled",true);
//I tried to to this but it didn't work too:
$("#myId").attr("disabled",true);
It disable all of my selects and not one.
How can I disable only "myId"?
Without seeing your HTML (which at the time of writing has not been supplied) it's very difficult for us to tell you why it's not working.
However, if $("#myId").attr("disabled",true); isn't working, then it suggests to me that you do not have an element in your HTML with id='myId'.
Things to check in the rendered HTML (as seen by the browser, not your code)...
Is there an element with an id of myId
Is the id exactly myId, and not myID for instance (as the case is important)
Are you using something like ASP.Net where naming containers could be changing the id of the rendered control to something like ctl00_myId
Do you have 2 elements with an id of myId... in which case, this is invalid HTML, as each element must have a unique id, and would result in jQuery only setting the disabled on the first item
It disables them all because $("input").attr("disabled",true); adds the attribute disabled to all input elements. Without seeing your HTML it's hard to tell what the reason is for it not disabling when you try using #myId
Here are some mistakes I've made in the past for similar problems:
1) I did not actually have the id on the element that I thought I had. Whether it was a misspelling, or capitalization difference, or underscore vs dash...the point is the id I was trying to reference on the page simply did not match the one I was looking for with jQuery
2) I referenced it as an id but really it was a class or vice versa. . for classes, and # for id's is second nature, but sometimes if you're tired or exhausted you can very easily make that mistake
3) I had given an id that existed in multiple elements. id is supposed to be unique by convention. Duplicate id's will produce unexpected behavior
Hopefully one of these simple reasons is the cause for your issue and you can quickly resolve it. Maybe take a 30 minute break and come back to it.

Show context-menus only when certain elements are clicked

I am kinda stuck with something and I need your help.
I am trying to show context-menus only when a user right-clicks on a certain elements in the page.
I thought I solve this problem by using getElementByClassName(...) and adding an onClick listener to each one of the elements, and when the user clicks on any of them I will then create the context-menus. And then remove the content menu later when everything is done.
Problem is that I don't have the full class names of those elements, all I know that they start with "story".
I am not sure how to go about doing this. Is there a way to use regex and getting all elements with a class name of story? Or is that not possible.
Thanks in advance,
There's this library that allows for regex selectors.
<div class="story-blabla"></div>
$("div:regex(class, story.*)")
However, you may not want to implement a full library. There's another solution:
$('div').filter(function() {
return this.class.match(/story.*/);
})
This will return the objects you want.
You can do this using attribute starts with selector
document.querySelectorAll("[class^=story]")

Remove unique ID from the DOM

I am working on a site that has a pretty funky modal box implemented and right now it is out of scope to implement something new so I am doing my best trying to work with what currently exists. The way it works is every time a new modal window is created it is assigned a unique ID.. for example
<div id="window_1308937649703" class="dialog">
To close the window the close button has an onclick like :
onclick='Windows.close("window_1308937649703", event)'
I am trying to destroy the window from another click event but I am unsure on what the best way to accomplish this would be. I am thinking I could use the dialog class to pull the associated unique #window_ id. Is there also some javascript I could use to getElementsByClassName('dialog') and remove it completely from the DOM ? I do have the Prototype library to work with as well if that is any help. I cant make much sense of the actual modal scripts so I am hoping for some kind of work-around solution.
To totaly remove the dialog from the dom use:
function removeNodeByID ( nodeId){
var node = document.getElementById( nodeId );
node.parentElement.removeChild(node);
};
with
onclick="removeNodeById('window_1308937649703')"
this way you just need the ID of the dialog which you mentioned you could retreive in the question.
There's not much you can do re: getElementsByClassName() in raw JavaScript (except rolling your own), although Prototype has some good functionality for this.
Another possible approach: does the close button have a generic ID? If so, and if you're able to add plugins (sorry, I've never used Prototype), you could look at this thread to get an idea how to trigger the click event on that close button once you've selected it.
As you have prototype you could simply use:
$$('.dialog').first().remove();
Also, if you are using prototype, you should probably avoid onClick, and use an event observer instead:
<button id="dialogremover">Remove</button>
<script type="text/javascript">
$('dialogremover').observe('click', function(ev) {
ev.stop();
$$('.dialog').first().remove();
});
</script>
This has two benefits:
It's much easier on the eyes!
It's possible to put the JS in an external script an clean up your HTML.

What information about a DOM element would allow JavaScript to identify it (somewhat) uniquely? (e.g. when it doesn't have `id`)

Here's what I'm trying to do: I have a bookmarklet that is looking for elements in the current page (which can be any site) and dispatch a click event on the ones that match. I have that part working.
In some cases though, nothing matches automatically and I want to be able to show (by hovering it) what element should be activated and then save some info about it in localStorage. The next time I'm using the bookmarklet on that page, I want to retrieve that info to identify the element in the DOM and then dispatch a click event.
The question is: what information should I save to be able to identify it? (in most cases, since it will always be possible to create a case where it doesn't work)
In the best case, said-element will have an id value and I'm good to go. In some other cases, it won't and I'd like to see your suggestions as to what info and what method I should use to get it back.
So far my idea is to save some of the element's properties and traverse the DOM to find elements that match everything. Not all properties will work (e.g. clientWidth will depend on the size of the browser) and not all types of elements will have all properties (e.g. a div node won't have a src value), which means that on one hand, I can't blindly save all properties, but on the other, I need to either choose a limited list of properties that will work for any kinds of element (at the risk of losing some useful info) or have different cases for different elements (which doesn't sound super great).
Things I was thinking I could use:
id of course
className, tagName would help, though className is likely to not be a clear match in some cases
innerHTML should work in a lot of cases if the content is text
src should work in most cases if the content is an image
the hierarchy of ancestors (but that can get messy)
...?
So, my question is a bit "how would you go about this?", not necessarily code.
Thanks!
You could do what #brendan said. You can also make up a jQuery-style selector string for each element in the DOM by figuring out the element's "index" in terms of its place in its parent's list of child nodes, and then building that up by walking up the DOM to the body tag.
What you'd end up with is something that looks like
body > :nth-child(3) > :nth-child(0) > :nth-child(4)
Of course if the DOM changes that won't work so good. You could add class names etc, but as you said yourself things like this are inherently fragile if you don't have a good "id" to start with, one that's put there at page creation time by whatever logic knows what's supposed to be in the page in the first place.
an approach would be using name, tagName and className-combination. innerHTML could may be too big.
another approach would be to look for child elements of your choosen element which have an id.
check for id => check for childs with id => check for name, tagName and className-combination (if => tell user to choose a different item :-)
What about finding all elements without an ID and assigning them a unique id. Then you could always use id.
What about using the index (integer) of the element within the DOM? You could loop through every element on page load and set a custom attribute to the index...
var els = document.getElementsByTagName("*");
for(var i = 0, l = els.length; i < l; i++) {
els[i].customIndex = i;
}

What is the easiest way to link radiobuttons to enable/disable other controls?

My webpage has a bunch of radiobuttons across a bunch of different radiobutton groups. Each radiobutton selection which is made will enable a directly corresponding element in the page and disable all other elements which correspond to the other radiobuttons in the group. What is the easiest way to make this link between the elements?
To use javascript-framework like jQuery by adding attribute 'disabled'.
For example:
$('#targetElement').attr('disabled', 'disabled');
Also you should keep in mind that it's easier to query for parent element and disable it's child elements.
Also, it's good to wait for the document being loaded and then add click-handlers on the radio controls
If you really want a slick way to do something like that, you should look into the eval(). It will allow you to dynamically execute a piece of code, based on a string. So, in your case, you can store this relation (maybe the ID of the corresponding element) as an attribute and then when any radio button is click. You extract this particular attribute and make an expression and eval() it to get it hide:
e.g. using jQuery:
eval( '$("#"' + some_attr + '").show()' );
However, this is generally not considered a good practise, but is pretty "automated".

Categories