A user can browse multiple img files with an <input type="file"> element. The selected file objects are than stored temporarily in an array and the attributes are shown to the user in a table build from div's and other elements.
This way the user can browse and select files multiple times and add them to the table or even delete some of them again before he finally upload the collection to the server.
While it is not a problem to append objects to an array and appending rows to a table so they match 1:1. It's getting tricky to delete rows from a table and elements of the array and keeping them matched.
So my question is if there is a nicer way to add/bind file objects to html elements, so when elements are deleted binded file objects are deleted as well ?
BTW I'm using pure JS.
I answer my question myself:
The easiest way to bind objects to a html element is described here by Osacr Paz. I tested it and it solves my problem.
Here is the answer copied from the link :
The easiest way is to do this:
<div id="myDiv">...</div>
In javascript
var myDiv = document.getElmentById('myDiv');
myDiv._variable = variable;
You can recover this later if you want, simply using the same myDiv variable, or, again, with document.getElementById() or any other DOM method that returns the element.
var variable = myDiv._variable;
The downside of doing it this way is that you can't specify, in the server, or from the markup, which object you want to attach to the element.
Related
I am creating a list of items that can be sorted using Mix It Up. I want to have an up and down button on each that increases or decreases the votes for each item and then based on the new votes, moves it up or down in the list.
This is all good and well, but I am running into issues with using data- attributes for Mix It Up. Mix It Up uses the data attributes to sort with, and so in my code I am changing the data-votes attribute (using $(selector).data('votes')). However, whenever I print out the elements with 'changed' data attributes, they are the same as they were at the beginning.
How can I force jQuery / Mix It Up to re-read the data attributes so that Mix It Up can then sort dynamically using the new ones?
I think you'll need to do:
$(selector).attr('data-votes', newCount);
If you're trying to read the attribute itself. You can chain it if you you want to set things through .data like...
$(selector).attr('data-votes', newCount).data('votes', newCount);
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
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?
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>';
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! ;)