pure javascript dom dynamic insert, update and delete - javascript

I want to know the most effctive way to dynamically update, insert or remove elements from an html page.
The outcome of this is that, I can change an input element into a div element and vice versa based on a user action.
eg
<form><input type="text" value="Value to save"/></form>
and based on some event, i will change that to
<form><div>Value to Save</div></form>
Tx

I think you could do this task this way (pure JS, without using external frameworks):
//retrieve the <form>
var form = document.getElementsByTagName('form')[0];
//retrieve the <input> inside the form
var input = form.getElementsByTagName('input')[0];
//create a new <div> DOM element
var newElement = document.createElement('div');
//The containing div text is equal to the input value (your case)
newElement.innerHTML = input.value;
//simple empty the form by set innerHTML = ""
form.innerHTML = "";
//append the <div> inside the form
form.appendChild(newElement);
By the way, I sugges you, if you want to manipulate DOM and do stuff like these in an easier way, learn how to do it by using frameworks like jQuery or mootools ;)

This is a general description:
Creating: You can create elements with document.createElement and then use one the various insertion methods to the insert the element at a certain position (e.g. Node.appendChild). You need to get references to related nodes first.
Most browser also support the innerHTML attribute for elements. You can set that attribute to an HTML(or text) string and the content of the element will be updated accordingly.
Updating: It depends on which data you want to update. E.g. an input element has an attribute value. In order to change the value of a text input you need to get a reference to that element first, then you can do element.value = 'new value'. For content, you can use the already mentioned innerHTML attribute.
Have a look at an HTML element reference to see what attributes they have.
Deleting: You want Node.removeChild.
I suggest to also have a look at DOM traversal methods and be aware of browser differences.

Using:
element.removeChild
element.appendChild
By using these methods, you can retain references to the elements in case you want to swap them back over again. Any event handlers in place will remain attached to the elements, too.

This depends on your definition of most effective.
If you mean the simplest way, then you can use a library like jQuery and do it like this:
$('form').html('<dynamic markup>');
If you mean the most performant way you can do the following:
document.getElementByTagName('form').innerHTML = '<dynamic markup>';

Related

Changing an elements ID using Javascript

I'm trying to change the id 'character' to 'characterSelected'
var character = document.getElementById('character');
var characterSelected = document.getElementById('characterSelected');
function klik() {
character.innerHTML = characterSelected;
}
character.addEventListener('click', klik);
This is what I have so far but it doensn't seem to work. I want to do this using Javascript only, no jQuery.
Thanks
You tried something, it didn't work. Now is the time to look up the standard properties and functions you're using incorrectly. If guessing doesn't work, always look for reliable documentation.
A good reference would be the Mozilla Developer Network (MDN). It's a wiki-style encyclopedia about the web, its standards and current browser compatibility. If you look at the page about innerHTML, you'll find the following:
The Element.innerHTML property sets or gets the HTML syntax describing
the element's descendants.
This means that the innerHTML property is used to replace the content of a tag as if you wrote that HTML inside it. Not what you want.
What you wanted was to change the id of an element. If you search for element id, you'll land on the Element.id page. And how practical, there's an example:
var idStr = elt.id; // Get the id.
elt.id = idStr; // Set the id
However, this is not going to fix your issues. You see, you guessed wrong when trying to use the getElementById function. This function looks at the page and finds the element with that id right now. If you don't have any element with the characterSelected id at first, then this variable you set is going to be null for the rest of time. Variables won't magically update when an element with that id is placed in the page.
And finally, you have missed the purpose of the id attribute itself.
Its purpose is to identify the element when linking (using a fragment
identifier), scripting, or styling (with CSS).
The purpose of an id is to identify an element uniquely. You might think: "that's what I'm doing". No. You're using an id to represent whether or not an element is selected. This is wrong. Depending on your objective, I would say: just store the selected element inside a variable. Then whenever you need to do something with the selected element, it's in that variable. If you need specific style for that element, then you could set a class to it. But the id isn't meant for this at all - in fact, an id isn't meant to change once an element is placed.

Replacing DIV with jQuery without removing it

I have a page which is generated and structured as a tree - nested DIVs, etc.. While the user views the page it is possible that some DIVs are updated on the server side and the changes are pushed to the client as JSON data, from which a DIV can be generated.
My problem is that even though I have the old DIV
var oldDiv = $('#foo');
and I have a new DIV generated by
var newDiv = generateDiv(jsonData);
I need to update the old one (both attributes and it's content) without deleting it. I was going to use the jQuery method .replaceWith() as such
oldDiv.replaceWith(newDiv);
but according to the documentation it is implemented as remove&create.
The .replaceWith() method removes content from the DOM and inserts new content in its place with a single call.
How can I update the old DIV without removing it? Is there some nice way to do this, or do I need to do it attribute by attribute?
As you've suggested, you may need to replace the attribute values individually. However, if it reads better, you can actually pass an object to the attr method, and it will update the values you supply.
oldDiv.attr({
attr1: newDiv.attr1,
attr2: newDiv.attr2,
attr3: newDiv.attr3
});
If you wanted to loop through the attributes to build the object, you could do that like this.
var newAttributes = {};
$.each(newDiv[0].attributes, function(index, attribute){
newAttributes[attribute.name] = attribute.value;
});
oldDiv.attr(newAttributes);
It cannot be done since a div element may contain many elements. Why dont u just append the new contents into it.
You can use jquery's append() method.
$(oldDiv).append("#new_div_id");
It will be appended as a child.
If at all you want to update any <p> element, you can use the html() function to get the contents of a tag and then
old_para_contents=("p").html();
$("p").html(old_para_contents+"New contents");
I've come up with one solution so far, but if anyone comes up with a better one, I will gladly assign it as the correct one. I need to make this as clean as possible.
var oldDiv = $('#my-old-div');
var newDiv = generateDiv(data);
oldDiv.attr("id", newDiv.attr("id"));
oldDiv.attr("class", newDiv.attr("class"));
//...
oldDiv.html(newDiv.html());

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?

PrototypeJS - Changing Elements Within HTML Variable

Is there a way to make calls within an HTML variable that is not in the DOM? For example, my code copies an existing row and then places it in the DOM. The problem is, I need to change some things within it. Code like:
newHTML = $$('.someRow')[0].innerHTML;
//Need to change form fieldName1 to fieldName2 in the newHTML variable, etc
$(this).up(1).insert({
before: newHTML
});
Right now I am changing things after, but it makes it difficult when there is a radio button that retains the same fieldname and changes the checked value of the original row.
Thanks.
You should be able to do this if you clone the node that you want to insert. e.g.
var newNode = $$('.someRow')[0].clone(true);
The cloned node is not inserted into the DOM until you insert it so you can manipulate it in whatever way you choose before doing so, its just a prototype Element.

How to select elements within a variable using jQuery?

I'm trying to make a simple image browser for TinyMCE which I am using in my CMS. As part of this I need to detect whether the user has selected an existing image, so I can display the "edit" form instead of the "choose an image form".
var selected_html = ed.selection.getContent();
var $elem = $(selected_html);
console.log($elem);
The first function returns the user selected text from the editor window as a string of HTML. I then would like to use jQuery (although plain javascript is just ok too) to check if this string contains an img tag before subsequently grabbing the src and title attributes for editing.
Now I've got as far as getting the html to turn into an object. But after this I can't manage to search it for the img element. After reading this (How to manipulate HTML within a jQuery variable?) I tried:
$elem.find('img');
But it just comes out as an "undefined" object...
I think I'm missing something fairly obvious here (it is getting late), but after an hour I still can't figure out how to grab the img tag from the selection. :(
Many thanks in advance.
Because the <img> is at the root of the jQuery object, you need to use .filter() instead of .find().
$elem.filter('img');
The .filter() method looks at the element(s) at the top level of the jQuery object, while .find() looks for elements nested in any of the top level elements.
If you're not sure beforehand where the target element will be, you could place the HTML into a wrapper <div> to search from. That way the HTML given will never be at the top.
var selected_html = ed.selection.getContent();
var $elem = $('<div>').html(selected_html);
var $img = $elem.find('img');
Try to see what is really inside your $elem variable. Just do a console.log($elem) using both Firefox and Firebug and you should be able to manage quite alright! ;)

Categories