YUI: String works, but a var containing a string doesnt? - javascript

var allRows = this.getTbodyEl().rows;
for (var i = allRows.length - 1; i >= 0; i--){
var thisRowID = allRows[i].id;
// Clean up any existing Drag instances
if (myDTDrags[thisRowID]) {
myDTDrags[thisRowID].unreg();
delete myDTDrags[thisRowID];
}
// Create a Drag instance for each row
myDTDrags[thisRowID] = new YAHOO.util.DDProxy(thisRowID);
};
I can't figure out why, but the above code is not yielding a DDProxy object for each row in my table. I have verified that the DDProxy code is all loaded and running properly by passing a string reference to a DOM element:
myDTDrags[thisRowID] = new YAHOO.util.DDProxy('yui-rec30');
This makes the corresponding row draggable as expected! I have also verified, using typeof, that the value of thisRowID is indeed of the type 'string' AND that the string contains the id of appropriate row elements.
What have I missed?

UPDATE: My code posted above is correct. I was wrong in that the contents of my thisRowID variable did NOT contain a reference to an appropriate row element!

Related

Deleting an element from JSON in javascript/jquery

I have a problem in deleting data from a JSON object in javascript. I'm creating this JSON dynamically and the removal shall also take place dynamically. Below is my JSON and the situation I'm in to.
{brands:[51,2046,53,67,64]}
Now, I have to remove 53 from this which I am calculating using some elements property, but I'm not able to remove the data and unable to find the solution for this situation. Please help me folks, thank you.
Try to use Array.prototyp.splice,
var data = { brands:[51,2046,53,67,64] };
data.brands.splice(2,1);
Since you want to remove an element from an array inside of a simple object. And splice will return an array of removed elements.
If you do not know the position of the element going to be removed, then use .indexOf() to find the index of the dynamic element,
var elementTobeRemoved = 53;
var data = { brands:[51,2046,53,67,64] };
var target = data.brands;
target.splice(target.indexOf(elementTobeRemoved),1);
You could write the same thing as a function like below,
function removeItem(arr,element){
return arr.splice(arr.indexOf(element),1);
}
var data = { brands:[51,2046,53,67,64] };
var removed = removeItem(data.brands,53);

Javascript: assign onclick inside class

I created a constructor that will handle a custom list control. I created a method in order to allow the user to add elements to the list, and I need to assign event handlers to the click events of the list elements (divs).
A simplified version of the code is here. The list elements are created using the innerHTML property and a string template upon which I substitute specific parts. Later I get the element by it's id and assign it a function in closure:
function prueba(){
var plantilla = '<div id="«id»">«texto»</div>';
var f = function(nombre){
return function(){console.log('mi nombre es ' + nombre)};
};
this.agregar = function(id, texto){
var tmp = plantilla.replace('«id»', id);
tmp = tmp.replace('«texto»', texto);
document.body.innerHTML += tmp;
document.getElementById(id).onclick = f(id);
};
};
The problem is that, apparently, the event handler is unasigned to previous created divs, so is only retained by the last one, as it can be tested with the following code:
var p = new prueba;
p.agregar('i1', 'texto1');
console.log(document.getElementById('i1').onclick.toString());//shows the function code
p.agregar('i2', 'texto2');
console.log(document.getElementById('i2').onclick.toString());//shows the function code
console.log(document.getElementById('i1').onclick.toString());//returns 'null' error
p.agregar('i3', 'texto3');
console.log(document.getElementById('i3').onclick.toString());//shows the function code
console.log(document.getElementById('i2').onclick.toString());//returns 'null' error
This happens in Iceweasel as well as in Chromium. It does NOT happen when I add 'onclick = f(«id»)' in the template (which I cannot do here because of the assigned function scope), and neither happens if I use document.createElement. What am I doing wrong?
You destroy elements previously created when you do this:
document.body.innerHTML += tmp;
Instead use insertAdjacentHMTL() if you want to append using HTML markup.
document.body.insertAdjacentHTML("beforeend", tmp);
Now instead of going through this destructive process...
serialize the existing DOM nodes to HTML
concatenate the new HTML fragment to the serialized nodes
destroy the old nodes
recreate the nodes with the new nodes
...it simply creates the new content and places it before the close of the body element.
Basically, remove element.innerHTML += ... from your coding practices. It's never necessary, it's inefficient and it causes problems like what you've described.
FYI, the .insertAdjacentHTML() method receives 4 different string possibilities as the first argument. Each one designates a position relative to the element on which you're calling it.
The strings are...
"beforebegin"
"afterbegin"
"beforeend"
"afterend"
The labels are pretty self-explanatory. They position the new content before the current element, inside the current element at the beginning, inside the current element at the end, or after the current element, respectively.
Your full code will look like this, which I shortened a bit too since the tmp really isn't needed here:
function prueba(){
var plantilla = '<div id="«id»">«texto»</div>';
var f = function(nombre){
return function(){console.log('mi nombre es ' + nombre)};
};
this.agregar = function(id, texto){
document.body.insertAdjacentHTML("beforeend",
plantilla.replace('«id»', id)
.replace('«texto»', texto));
document.getElementById(id).onclick = f(id);
};
};

How do I copy an HTML document and edit the copy based upon the selection, without altering the original document?

I have an HTML document, and I would like to remove some of the tags from it dynamically using Javascript, based on whether the tags are within the current selection or not. However, I do not want to update the actual document on the page, I want to make a copy of the whole page's HTML and edit that copy. The problem is that the Range object I get from selection.getRangeAt(0) still points to the original document, as far as I can see.
I've managed to get editing the original document in place with this code:
var node = window.getSelection().getRangeAt(0).commonAncestorContainer;
var allWithinRangeOfParent = node.getElementsByTagName("*");
for (var i=0, el; el = allWithinRangeParent[i]; i++) {
// The second parameter says to include the element
// even if it's not fully selected
if (selection.containsNode(el, true) ) {
el.remove();
}
}
But what I want to do is to somehow perform the same operation with removing elements, but remove them from a copy of the original HTML. I've made the copy like this: var fullDocument = $('html').clone(); How could I accomplish this?
Either dynamically add a class or data attribute to all your elements on load before you clone so that you have a point of reference then grab the class or data attribute on the common ancestor and remove it from the clone. I can give an example if you like? Along these lines - http://jsfiddle.net/9s9hpc2v/ isn't properly working exactly right but you get the gist.
$('*').each(function(i){
$(this).attr('data-uniqueId', i);
});
var theclone = $('#foo').clone();
function laa(){
var node = window.getSelection().getRangeAt(0).commonAncestorContainer;
if(node.getElementsByTagName){
var allWithinRangeOfParent = $(node).find('*');
console.log(allWithinRangeOfParent, $(allWithinRangeOfParent).attr('data-uniqueId'));
$.each(allWithinRangeOfParent, function(){
theclone.find('[data-uniqueId="'+$(this).attr('data-uniqueId')+'"]').remove();
});
console.log(theclone.html());
}
}
$('button').click(laa);

Something about this 'NOT_FOUND_ERR: Dom exception 8' confuses me

Well, here I continue, trying to learn this very nice language... So I previously had a very ugly code full of 'document.write()' and more ugly things, and now I am transforming it into a very nice standards compliant code, and I am liking it! But I found a problem where I don't see the logic. Here it goes:
In the html file I have this:
<body onload="generatetable(0)">
And in the .js file I have this:
function generatetable(product) {
var tbinfo = document.createElement("table"); //table
var tbbody = document.createElement("tbody"); //tbody
var row = document.createElement("tr"); // creates row
for (var i = 0; i < 4; i++) { // creates 4 cells
var cell = document.createElement("td");
}
var tname = arraypro[product].Name;
cell.appendChild(tname);
(I don't paste the rest of the table, because it seems to work fine)
And when running, I get the 'Exception 8' error on the var tname = arraypro[product].Name line
But if I do just an
alert(arraypro[0].Name);
it outputs exactly what it should output, the very right word. How it's possible that the value in arraypro[product].Name can be retrieved by an alert (if you pass the value of 'product') but not by the appendChild?
I am still not very well used to the logic of programming, but I try...
PD: The arraypro , where the information is, has been declared as a global value, accessible for everything, in case it matters to know.
Thanks very much for any input here.
appendChild() expects a DOM-Node, you're passing in a string I believe.
You can change it to:
var tname = arraypro[product].Name;
cell.appendChild(document.createTextNode(tname));

surroundContents() make changes `live`?

Links to live examples # jsfiddle & jsbin.
So this function:
function symbolize(e){
var elements = e.childNodes; // text nodes are necessary!
console.log(elements);
for(var i=0; i < elements.length; i++){
t = elements[i];
var range = document.createRange(), offset = 0, length = t.nodeValue.length;
while(offset < length){
range.setStart(t, offset); range.setEnd(t, offset + 1);
range.surroundContents(document.createElement('symbol'));
offset++;
}
}
}
..should iterate over every letter and wrap it in a <symbol/> element. But it doesn't seem to be working.
So I added the console.log(); right after the *.childNodes have been fetched, but as you'll see in the example site above, the log contains 2 unexpected elements in front(!) of the array. And yeah, because of this, I have a feeling that surroundContents(); make the changes live(!). couldn't find any reference on this though
One of the elements is an empty Text node, the other is my <symbol/>. But yeah, this is totally unexpected result and messes up the rest of the function.
What could be wrong with it?
Thanks in advance!
Update
Oh, looks like the elements are added on Chrome, Firefox doesn't add the elements, but still halts the function.
Element.childNodes is indeed a live list , it could not be otherwise (that would mean an incorrect list of nodes). The easiest solution is to freeze (make a copy of) it before you mess with it (by surrounding existing ranges).
var elements = Array.prototype.slice.call(e.childNodes, 0);
https://developer.mozilla.org/en/childNodes it's of type NodeList
https://developer.mozilla.org/En/DOM/NodeList those are live lists

Categories