How to get element from template by javascript? - javascript

I dont know good method how to get DOM element from template by javascript.
Example template:
<script id = "template" type="text/template">
<div>text1</div>
<div>text2</div>
<div>text3</div>
</script>
For example i want get div with "text2"
There is ways which i know, all of them are bad:
Add "class" to all elements - it breaks semantics (class created for CSS). In big projects you must use very long names for classes, its very inconvenient.
Get element by his number (index) - when adding a new element, you must rewrite old numbers in your code.

I see a couple of options:
If you don't want to use class , you can use a data-* attribute.
Assuming you load the template once and then duplicate its contents as desired, you could put id values on the elements in the template, which you then remove when cloning them and adding them to the document (so you don't end up with the same id on more than one copy of the element, which would be invalid and probably counterproductive).

Maybe you can also create as many templates as you need.
One for each div.
If you need to get each div at a time you must set ids to them ... of course you can also browse the dom inside script element to find the one you're interested in ...
Home this helps
Regards
mimiz

Related

jQuery child elements with same ID

Imagine that I have this HTML structure:
<div id="bodyRead">
...
<div id="List"></div>
</div>
...
<div id="bodyWrite">
...
<div id="List"></div>
</div>
As you can see, I have the #List inside two different divs (bodyRead and bodyWrite). For a lighter code, I preferred to work with id instead of class (even knowing that duplicate IDs isn't valid, the code makes more sense to me), and selecting the #List on jQuery like this:
$('#bodyRead #List').off('click').on('click', function() ...
$('#bodyWrite #List').off('click').on('click', function() ...
works. I'm always taking care of make duplicate IDs only on child divs, where I can separate them by their parent div on jQuery selector.
Is this approach very wrong? I mean, this can get me in trouble?
don't duplicate your Id even in child element .. change it to class="List"
then you can use
$('.List').on('click',function(){
var getparent = $(this).parent().attr('id');
alert(getparent);
});
and if class="List" not first level child of any of #bodyRead or #bodyWrite
add class to it
<div id="bodyRead" class="mainDiv">
<div id="bodyWrite" class="mainDiv">
and then use
$('.List').on('click',function(){
var getclosest = $(this).closest('.mainDiv').attr('id');
alert(getclosest);
});
You should expect that CSS and JavaScript (including jQuery and other frameworks) behave in accordance with the HTML specifications. ID must be unique, multiple instances of the same ID is not supported. See below:
From HTML 4.01 spec:
id = name [CS] This attribute assigns a name to an element. This name
must be unique in a document.
class = cdata-list [CS] This attribute
assigns a class name or set of class names to an element. Any number
of elements may be assigned the same class name or names. Multiple
class names must be separated by white space characters.
http://www.w3.org/TR/html401/struct/global.html#h-7.5.2
This is from the HTML 5 spec:
3.2.5.1 The id attribute
The id attribute specifies its element's unique identifier (ID). [DOM]
The value must be unique amongst all the IDs in the element's home
subtree and must contain at least one character. The value must not
contain any space characters.
There are no other restrictions on what form an ID can take; in
particular, IDs can consist of just digits, start with a digit, start
with an underscore, consist of just punctuation, etc.
An element's unique identifier can be used for a variety of purposes,
most notably as a way to link to specific parts of a document using
fragment identifiers, as a way to target an element when scripting,
and as a way to style a specific element from CSS.
Identifiers are opaque strings. Particular meanings should not be
derived from the value of the id attribute.
Well i feel this is a bad approach because the browser creates the DOM(document object model) for the page, which takes into consideration that each Id has a unique value.It would be hard to play with the duplicate Id's in javascript when you want to manipulate you need to consider parent as well as child id each time. So its better to use classes instead.
Although id selectors are meant to be unique your code will work as long as you make sure to use correct nesting. In other words #bodyRead #List and #bodyWrite #List are perfectly fine as long as you don't create ambiguity by leaving out the parent selectors to #List.
Still, using multiple identical ids on the same page is just asking for trouble. You should reconsider switching to class selectors or reevaluate if it is really worth the potential trouble of sticking with your original idea.
You certainly should not use duplicate id's in an html page. If you have a similar concept within two different div's then class makes more sense anyway. So change the List ids to classes and then you can access them like this:
$('#bodyRead .List').off('click').on('click', function() ...
$('#bodyWrite .List').off('click').on('click', function() ...
Even if your code works now due to how jQuery works, because the html specifications say not to do this, you can not know for certain that your code will continue to work in the future.

Store "templates" of children

I am new to JavaScript so forgive me if the question comes around as dumb.
I know that appendChild() allows me to add a child element to an existing element. However, the problem is that I want to add an element which has an image on the left and a series of text boxes on the right and I need to add it over and over again on button click.
Adding simple elements like p, a , etc can be done by a single call to appendChild(), however for the above scenario, it will be a little messy.
Is there some way that I can define the custom element that I want to append and then just add it with a single call to appendChild()
Are you using jQuery? If it is a really complicated template, you could use .load() to ajax in an template and populate it with whatever you have to. You wouldn't need to dynamically create all of the elements using javascript, only populate it. This would would also allow you to change your template if need be very easily.
It seems you need cloneNode:
target.appendChild(template.cloneNode(true)); // If you want to clone template
// with all its descendants
target.appendChild(template.cloneNode(false)); // If you want to clone template
// without its descendants
I do this quite a bit. My code generally looks like this:
<div class="template" style="display: none;">stuff</div>
then:
$('.template').clone(true).removeClass('template').show().appendTo(someElement);
Since you're not using jQuery, have a look at the clone function here:
http://code.jquery.com/jquery-1.11.0.js
(search for "clone: function" to find it)
You can steal the relevant bits if you can't actually use jQuery itself.

How to use common js function for two divs containig elements of identical ids?

I have common jQuery function and two div tags. Both div tags have different names but both containing elements of identical ids now i want to use this common Jquery function for them both?
I have implemented common function but it's not working for both.
Here's link to my jsfiddle -jsfiddle.net/xS7zF/1/
In my jsfiddle there are two div tags namely example1 and example2 and both tags have elements of identical ids. Function is working fine for first div but not for second.
please help me to sort out this.
Yeah, under the hood, jQuery selection on an ID will use the Document.GetElementById() function implemented by the browser, which is really fast, but (i guess depending on the browser) will stop after it finds the first element, since ID's should be unique and no further searching is needed after the first one is found.
For instance, rename the divs with id="eb" to class="eb" and you can still target specific elements using $("#example1 .eb") and $("#example2 .eb")
UPDATE:
Using your new Fiddle I created this: http://jsfiddle.net/xS7zF/5/
I cleaned up a lot of code and hopefully you can see what I have done. I changed all elements that appear twice from id to class. Now, when you attach an event to an element using $(".classname").click(), it attaches to all the elements. In the handler function where you set HTML and do your show()/hide(), you don't target a specific element using it's ID, but you find it relative to the element that does the event. You can do this using parent(), parentsUntil(), next(), find(), etc. Check jQuery docs for all possibilities. So for instance, the change-handler attaches to all inputs with name=Assets. But instead of doing $("#b1").show(), I go to the parent of the specific input that fires using $(this).parent(). Then I find the element with a class=".b1", which it will only find the one that is next to this specific input and I set the HTML to just that element.
Since there is another input, the same actions happen when THAT input changes, but instead it finds IT's parent, and finds the element with class=".b1" that is next to IT. So both divs with input are contained since they act on elements relative to itself and not across the document.
For extra fun and to show you how flexible this way of programming is, here is a fiddle with the Javascript-code unchanged, but with the exact same question-div copied 8 times. No matter how many times you repeat this, the same code will act on as many divs as you create since everything works relative. http://jsfiddle.net/xS7zF/7/
Hopefully this helps, the rest is up to you!
ID's must be unique, you should not repeat them. You could replace id with class and in the jQuery function do (".ub").each() or manually referencing the object using eq(x). e.g. (".ub").eq(1).
You shouldn't assign same id's to different elements.
You CAN but you SHOULDN'T. Instead of giving the same id, use class
IDs must be unique, try fix this, change to classes.
You can try something like this:
$("div div:first-child")
instead of
$("#eb")
But depends of the rest of your page code. So, change to classes first and use
$(".eb")
when jQuery / javascript find the first ID it would ignore the rest, please read more about it
http://www.w3schools.com/tags/att_global_id.asp

How can I access a particular div on a page which has the same id in two places?

This is the same question as this:
Referring to a div inside a div with the same ID as another inside another
except for one thing.
The reason there are two elements with the same ID is because I'm adding rows to a table, and I'm doing that by making a hidden div with the contents of the row as a template. I make a new div, copy the innerhtml of the template to my new div, and then I just want to edit bits of it, but all the bits have the same ID as the template.
I could dynamically create the row element by element but it's a VERY complex row, and there's only a few things that need to be changed, so it's a lot easier to just copy from a template and change the few things I need to.
So how do I refer to the elements in my copy, rather than the template?
I don't want to mess up the template itself, or I'll never be able to get at the bits for a second use.
Or is there another simpler way to solve the problem?
It will probably just be easiest when manipulating the innerHtml to do a replace on the IDs for that row. Maybe something like...
var copiedRow = templateRow.innerHTML.replace(/id=/g,"$1copy")
This will make the copied divs be prefixed with "copy". You can develop this further for the case that you have multiple copies by keeping a counter and adding that count variable to the replace() call.
When you want to make a template and use it multiple times its best to make it of DOM, in a documentFragment for example.
That way it doesn't respond to document.getElementById() calls in the "live" DOM.
I made an example here: http://jsfiddle.net/PM5544/MXHRr/
id's should be unique on the page.
PM5544...
In reality, there's no use to change the ID to something unique, even though your document may not be valid.
Browsers' selector engines treat IDs pretty much the same as class names. Thus, you may use
document.querySelector('#myCopy #idToLookFor');
to get the copy.
IDs on a page are supposed to be unique, even when you clone them from a template.
If you dynamically create content on your page, then you must change the id of your newly cloned elements to something else. If you want to access all cloned elements, but not the template, you can add a class to them, so you can refer to all elements with that class:
var clonedElement = template.cloneNode(yes); // make a deep copy
clonedElement.setAttribute("id", "somethingElse"); // change the id
clonedElement.setAttribute("class",
clonedElement.getAttribute("class") + " cloned"
);
To access all cloned elements by classname, you can use the getElementsByClassName method (available in newer browsers) or look at this answer for a more in-depth solution: How to getElementByClass instead of GetElementById with Javascript?
Alternatively, if you have jQuery available, you can do this is far less lines of code:
$("#template").clone().attr("id","somethingElse")
.addClass("cloned").appendTo("#someDiv");
The class lookup is even simpler:
$(".cloned").doSomethingWithTheseElements();
Try to avoid using IDs in the child elements of the cloned structure, as all ids of the cloned element should be changed before adding the clone to the page. Instead, you can refer to the parent element using the new id and traverse the rest of the structure using classnames. Class names do not need to be unique, so you can just leave them as they are.
If you really must use ID's (or unique "name" attributes in form fields), I can strongly suggest using a framework like jQuery or Prototype to handle the DOM traversal; otherwise, it is quite a burden to resolve all the cross-browser issues. Here is an example of some changes deeper in the structure, using jQuery:
$("#template").clone().attr("id","somethingElse")
.addClass("cloned") // add a cloned class to the top element
.find("#foo").attr("id","bar").end() // find and modify a child element
.appendTo("#someDiv"); // finally, add the node to the page
Check out my ugly but functional cheese. I wrote a function that works like getelementbyid, but you give it a start node instead of the document. Works like a charm. It may be inefficient but I have great faith in the microprocessors running today's browsers' javascript engines.
function getelement(node, findid)
{
if (node)
if (node.id)
if (node.id == findid)
return node;
node = node.firstChild;
while(node)
{
var r = getelement(node, findid);
if (r != null)
return r;
node = node.nextSibling;
}
return null;
}
When you copy the row, don't you end up having a reference to it? At that point can't you change the ID?

JavaScript String .replace method is replacing all my content?

I have successfully implemented finding and replacing some text with something else in the following way:
$(".class").html($(".class").html().replace(/\text\b/g, '<span class="newclass newclass2">new text</span>'));
When I apply this to my element 'class' it finds all the 'text' and replaces with 'new text' and everything relating to the new classes.
However, if I have more than one element on the page with the same class, it replaces all the classes with whatever text is in the first class.
For example, if my first class has the content "Hello everyone", when the script is applied to this class, it works fine. Any subsequent class of the same name is then replaced with "Hello everyone". These also have the function applied in the same way as the first occurrence of that class.
IE, it applies the script, then replicates this in every single class of the same name on the page.
I do not understand why it would do this, and rather renders the function pointless in many ways if it can't be used to change text throughout different sections without setting up new scripts and different classes.
Hopefully there is something simple at work here that I am not aware of, any help would be much appreciated.
Many thanks
Richard
That is the nature of class selectors--the .html(...) will replace the HTML of everything that matches the .class selector.
If you want to replace text in each individual .class element, you can use the .each function. (There are probably jQuerier ways, too.)
$(`.class`).each(function(n, el) {
var myHtml = $(this).html();
myHtml = mungeIt(myHtml);
$(this).html(myHtml);
});
If you want to select only an individual .class element, then you either (a) don't really want to be using classes, but IDs, or (b) need to understand enough of your structure or the context you wish to operate in to select only the targeted DOM element.
(And hope the structure or context doesn't change without a corresponding code update.)
You're specifying a class with the jQuery selector $(".class") That's what the period indicates. jQuery has a ton of selectors to choose from. A list is provided in the documentation here: http://api.jquery.com/category/selectors/
Also, I'd look at http://api.jquery.com/hasClass/ for your problem as you could then use if...then statements to not run into others
Dave is right about needing to use the .each method. We need to loop through each element at a time because .html() will only return the first element when there are multiple matches.
Try:
$('.class').each(function() {
$(this).html($(this).html().replace(/someWord/g,'withAnother'));
});

Categories