How to use obj.init in my document.getElements? - javascript

I am new to this framework and I am just converting my javascript/jquery to ajax.
I have this code:
var Obj = {
Init:function(config){
this.config = config;
this.BindEvents();
},
BindEvents:function(){
$this = Obj.config;
Obj.ReturnArray();
},
ReturnArray:function(){
$this = Obj.config;
for(x = 0; x < itemNames.length; x++){
var obj = {itemName:itemNames[x],itemPrice:itemPrices[x]};
console.log(obj);
prods.push(obj);
}
for(var ctr = 0; ctr < prods.length; ctr++){
var rows = parseInt(document.getElementById("modalTable").getElementsByTagName("tbody")[0].rows.length);
var table = document.getElementById("modalTable").getElementsByTagName("tbody")[0];
}
}
}
Obj.Init({
modalTable : $("#modalTable"),
mainTable : $("#mainTable"),
btnAddToTable : $("btnAddToTable"),
mainCellQuantity : $(".mainCellQuantity"),
mainTBody : $("#mainTBody")
});
But I want to you use the object being initialized in Obj.Init({});
var rows = parseInt(document.getElementById("modalTable").getElementsByTagName("tbody")[0].rows.length);
var table = document.getElementById("modalTable").getElementsByTagName("tbody")[0];
just to be like this
var rows = parseInt(modalTable.mainTbody.rows.length);
To sum it all, I want all javascript's document be objects. Is there any way to do that?

I am by phone so cannot try it.
In my understanding you want that all the dom elements inherit from your Obj.
Considering that all the document objects inherit from Element, what you could try is to extend the Element prototype with your prototype.
It could be something like:
Element.prototype = Object.create(Obj.prototype);

So, someone suggested to use jquery.each() so I tried, and luckily, I solved my problem. I'll share my answer so anyone might see this helpful
$.each(prods_(this_is_the_array)_, function(index){
var row = modalTBody_(the_tbody)_.insertRow(index);
});

Related

Use closure inside array with pure javascript

I need to copy a string inside an array to a value inside another array that is created in a loop. In the end when I print all names are the last in the array of names. I want to copy/clone the value so that I don't have a reference and I would like it to be only in native javascript without external libraries.
This is my code
var exp_names =["name1","name2","name3"];
var i;
for (i = 0; i < exp_names.length; i++) {
d3.tsv("data/"+exp_names[i], function(data) {
data.forEach(function(d){
//Do stuff with my tsv
d.expId = exp_names[i];
});
});
});
And then all expId are "name3"
Data is loading correctly per file.
I have tried with jquery's extend function and also lodash's clone function, I have tried my own clone function and nothing works it will still throw "name3" for all the expId.
These didn't work:
var newname = new String(exp_names[i]);
var newname = $.extend(true, {}, exp_names[i]);
var newname = $.extend( {}, exp_names[i]);
var newname = _.clone(exp_names[i]);
var newname = exp_names[i].slice(0);
I am desperate by now.
You need to use bind function.
var exp_names =["name1","name2","name3"];
var i;
var func = [];
for (i = 0; i < exp_names.length; i++) {
func[i]=(function(index){
d3.tsv("data/"+exp_names[index], function(data) {
data.forEach(function(d){
//Do stuff with my tsv
d.expId = exp_names[index];
});
});
}).bind(this,i);
}
for(i = 0; i < 3; i++){
func[i](i);
}
Another solution is to use let keyword.
ES6 provides the let keyword for this exact circumstance. Instead of using closures, we can just use let to set a loop scope variable.
Please try this:
for (let i = 0; i < exp_names.length; i++) {
d3.tsv("data/"+exp_names[i], function(data) {
data.forEach(function(d){
//Do stuff with my tsv
d.expId = exp_names[i];
});
});
}
I guess usage of IIFE and bind together, in the first answer is a little weird. It's best to choose either one of them. Since in the newest versions of the browsers bind is way faster than an IIFE closure and the let keyword I might suggest you the bind way.
A similar example to your case might be as folows;
var exp_names = ["name1","name2","name3"],
lib = {doStg: function(d,cb){
cb(d);
}
},
data = [{a:1},{a:2},{a:3}];
for (i = 0; i < exp_names.length; i++) {
lib.doStg(data, function(i,d) {
d.forEach(function(e){
//Do stuff with doStg
e.expId = exp_names[i];
console.log(e);
});
}.bind(null,i));
}

Elements not added to DOM by generator function

I have been pulling my hair out trying to make this simple code work. It should render input fields in the given DOM, but it doesn't. Why not?
var elems = 10;
function generateElems() {
for (var i = 0; i < elems; i++) {
document.getElementsByTagName("div")[0].appendChild(document.createElement('input'));
}
//Clean up
var obj = null;
var elems = null;
}
generateElems();
Working DEMO
You are dealing with JavaScript variable hoisting here. Remove this line var elems = null; and your code should work.
It is considered best practise in JavaScript to declare all variables at the top of the function body.
Read this article for more information on JavaScript hoisting.
As we are discussing best practises, it's worth making a note that appending elements in loops is a bad idea for performance. You should use createDocumentFragment instead to append the elements to and then dump this to DOM. It saves expensive document reflows and makes significant difference in performance.
var elems = 10;
function generateElems() {
var d=document.createDocumentFragment();
for (var i = 0; i < elems; i++) {
d.appendChild(document.createElement('input'));
}
document.getElementsByTagName('div')[0].appendChild(d);
//Clean up
//var obj = null;
//var elems = null; ----> Commented out this line, it was causing the problem.
}
generateElems();
Don't set elms to null.
var elems = 10;
function generateElems() {
for (var i = 0; i < elems; i++) {
document.getElementsByTagName("div")[i].appendChild(document.createElement('input'));
}
}
generateElems();

making getelementbyid plural

In the context of the code below (or anywhere), is it possible for a getelementbyid function to work plurally? Or do I need a different function, or possibly Jquery?
<script type="text/javascript">
window.onload = function()
{
var test = document.getElementById('test');
if (test)
{
test.className = 'unactive';
test.firstChild.onclick = function()
{
if(this.parentNode.className == 'unactive') {
this.parentNode.className = 'active';
}
else
{
this.parentNode.className = 'unactive';
}
}
}
};
</script>
You can use this;
document.getAllById = function(id){
if(document.all)
return document.all[id];
var elements = [],
all = document.getElementsByTagName('*');
for(var i=0;i<all.length;i++)
if(all[i].getAttribute('id')===id)
elements.push(all);
return elements;
}
Anyway, as #Pointy said, the id attribute is supposed to be unique, while class is used to define one or more elements that has some common properties
I assume you want to act on multiple elements using a list of IDs. (If I am wrong, and you actually want to select multiple elements with the same ID, you have done a Bad Thing, since IDs should be unique. In that case, you should use classes instead.)
In jQuery, you can accomplish this with a comma-separated list of id selectors (like $("#foo, #bar, #baz")) and implement your function like:
$("#foo, #bar, #baz").addClass("unactive")
.children(":first-child").click(function() {
var $this = $(this);
var $parent = $this.parent();
$parent.toggleClass("active unactive");
});
Without jQuery, this small function takes a list of IDs and results an array of nodes:
document.getElementsByIdList() {
var results = [];
for(var i=0; i<arguments.length; ++i) {
results.push(document.getElementById(arguments[i]));
}
return results;
}
Use it with you current code with:
var myNodeArray = document.getElementsByIdList("foo", "bar", "baz");
for(var i=0; i<myNodeArray.length; ++i) {
var test = myNodeArray[i];
if(test) {
// your code goes in here...
}
}

OO JS - loop through object array

Quite new to OO Js, used to program with function after function so trying to fix that now!
I'm making a tab layout -
I create a tab by calling: tab.NewTab();
I can access the tabs at tab[0], tab[1] etc
var tabCount = 0;
var tabs = [];
tabs.NewTab = function (){
var tabName = "tab" + tabCount;
tabs[tabCount] = new Tab(tabName);
tabCount++;
};
function Tab(tabName){
return{
name: tabName
}
}
I wanted to make a function that counts how many tabs are open:
tabs.HowMany = function () {
for (var i in tabs) {
alert("new");
}
};
This is returning the methods too (0,1, NewTab, HowMany).
Any advice?
You're looking for tabs.push(new Tab(tabName));
Then ditch tabCount, and instead use the length property native to all javascript arrays: tabs.length
Also, your Tab constructor is wrong. As it is currently written it should not be called with new. Just call Tab('someName') and it will return to you the object you're looking for. If you do that however, change it to tab since non-constructor functions should be lowercase.
If you're really eager to use the new keyword, this is what Tab should look like:
function Tab(tabName){
this.name = tabName;
}
EDIT
If you want to iterate over all members of your array, this is the simplest way:
for (var i = 0; i < tabs.length; i++)
var currentTab = tabs[i];
You need to change var tabs = []; to var tabs = new Array();.
And add items to it using tabs.push(new Tab(tabName));
Simple count:
var count = tabs.lenght
Enumeration of items:
for (var i = 0; i < tabs.length; i++) {
alert(tabs[i]);
}
You could do:
tabs.HowMany = function () {
for (var i in tabs) {
if(tabs.hasOwnProperty(i)){
if(typeof tabs[i] !== 'function'){
alert('new')
}
}
}
};
but you'd better switch using it as array
tabs.push(new Tab(tabName))
tabs.HowMany = function () {
return tabs.length
};

how to turn this to into a tree?

I was doing a challenge of building a tree from all html elements. And I am 90% done, but I got stuck...
How do I change this string into a tree?:
mystring= "red1/(none)-red2/red1-blue1/red2-blue2/red2-blue3/red2-red3/red1-red4/red3-red5/red4-red6/red5-blue4/red6";
After splitting them by "-" we will have:
10 groups of -> (parameter1)/(parameter2)
The first parameter it is the object,
The second parameter is the 'in-what-it-will-be-contained'
I have no idea how to move every 'parameter1' inside 'parameter2'. (note: sometimes the parameter1 will be the parameter2 of a parameter1)
Visual example of what I mean with a parameter is inside another parameter: (this example uses exactly the string above)
Probably we should use arrays?, idk... I am totally lost :sadface:
I think this is a little more concise and straight forward. It uses an object as a dictionary to lookup the parent, rather than a function that has to recursively iterate the tree to find the parent. That recursive function is expensive. An object lookup is quick.
First, for convenience, I'd define an object type:
function TreeNode(name) {
this.Name = name;
this.Children = [];
}
Then I'd add a method to do the work. This parses your tree string:
TreeNode.ParseTree = function (treeString) {
var root = new TreeNode("");
var nodes = {};
var pairs = treeString.split("-");
pairs.forEach(function(pair) {
var parts = pair.split("/");
var parentName = parts[1];
var childName = parts[0];
var node;
if (parentName == "(none)") {
node = root;
root.Name = childName;
}
else {
node = new TreeNode(childName);
nodes[parentName].Children.push(node);
}
nodes[childName] = node;
});
return root;
};
That's it! Now, to get visual representations of your tree, you can add some prototype methods to TreeNode. First, override .toString():
TreeNode.prototype.toString = function(indent) {
indent = indent || "";
var strings = [indent + this.Name];
this.Children.forEach(function(child) {
strings.push(child.toString(indent + " "));
});
return strings.join("\n");
};
Then, add a .Render() method to display the tree within a web page:
TreeNode.prototype.Render = function(container) {
var nodeEl = container.appendChild(document.createElement("div"));
nodeEl.className = "treeNode";
var nameEl = nodeEl.appendChild(document.createElement("div"));
nameEl.className = "treeNodeName";
nameEl.appendChild(document.createTextNode(this.Name));
var childrenEl = nodeEl.appendChild(document.createElement("div"));
childrenEl.className = "treeNodeChildren";
this.Children.forEach(function(child) {
child.Render(childrenEl);
});
return nodeEl;
};
Here it is in action: http://jsfiddle.net/gilly3/wwFBx/
Edit: I didn't notice the jQuery tag in your post, here's a render method that's all jQuery, and produces simpler HTML which you seem to imply is what you want:
TreeNode.prototype.Render = function(container) {
var el = $("<div>").appendTo(container).text(this.Name);
$.each(this.Children, function() {
this.Render(el);
});
return el;
};
This JSFiddle uses jQuery, even replacing Array.forEach with $.each: http://jsfiddle.net/wwFBx/1/
As an alternative, you might consider just serializing your tree as JSON. Eg:
"{\"Name\":\"red1\",\"Children\":[{\"Name\":\"red2\",\"Children\":[{\"Name\":\"blue1\",\"Children\":[]},{\"Name\":\"blue2\",\"Children\":[]},{\"Name\":\"blue3\",\"Children\":[]}]},{\"Name\":\"red3\",\"Children\":[{\"Name\":\"red4\",\"Children\":[{\"Name\":\"red5\",\"Children\":[{\"Name\":\"red6\",\"Children\":[{\"Name\":\"blue4\",\"Children\":[]}]}]}]}]}]}"
or maybe:
"{\"red1\":{\"red2\":{\"blue1\":{},\"blue2\":{},\"blue3\":{}},\"red4\":{\"red5\":{\"red6\":{\"blue4\":{}}}}}}"
Parse the string via JSON.parse().
Disclaimer: I've referenced Array.forEach() and JSON.parse() which are built-in to modern browsers but are not supported by older browsers. To enable these functions in older browsers, see this documentation on Array.forEach() and this shim for JSON.parse().
Here's about how I would do it, using an array of "unplaced" elements and looping through it until they're all placed:
var str = "red1/(none)-red2/red1-blue1/red2-blue2/red2-blue3/red2-red3/red1-red4/red3-red5/red4-red6/red5-blue4/red6";
var unplaced = [];
var tree = null;
var elements = str.split(/[\/\-]/);
function findNodeByName(nodeName, context) {
if(context.name === nodeName) return context;
for(var i = 0; i < context.children.length; i++) {
var subSearch = findNodeByName(nodeName, context.children[i]);
if(subSearch) return subSearch;
}
return null;
}
var element, node, parent, thisElement, i;
for(i = 0; node = elements[i]; i += 2) {
node = elements[i];
parent = elements[i + 1];
thisElement = {name: node, children: []};
if(!tree && parent === '(none)') {
tree = thisElement;
} else if(tree) {
var parentNode = findNodeByName(parent, tree);
if(parentNode) {
parentNode.children.push(thisElement);
} else {
unplaced.push(thisElement);
}
}
}
var oldLength;
while(unplaced.length) {
oldLength = unplaced.length;
for(i = 0; element = unplaced[i]; i++) {
var parentNode = findNodeByName(parent, tree);
if(parentNode) {
parentNode.children.push(element);
unplaced.splice(i, 1);
i--;
}
}
if(oldLength === unplaced.length) {
throw new SyntaxError("The string is not a valid tree.");
}
}
// The result is contained in "tree".
You can see the result at: http://jsfiddle.net/minitech/tJSpN/
One with a function: http://jsfiddle.net/minitech/tJSpN/1/
And one with more error-checking: http://jsfiddle.net/minitech/tJSpN/2/
Actually, I found a simpler/shorter/neater way using the JQuery function AppendTo()
We just need to:
Split the parameters...
Create one div for each (parameter1)
Use a loop to move every (parameter1) inside (parameter2) using the
AWESOME AppendTo() function that JQuery offers
The best thing is that they are actually inside them, so you can easily put a Hide/Show effect to make a cool effect
You may try to create tree nodes of the form :
node = {
str:"red1",
subBranches : new Array()
}
Once you have that, you may add the sub-branches iterating through the array, adding such nodes for each found correct couple, and removing the couples already placed in rootNode.subBranches. Then you recursively do the same for every sub-branche.

Categories

Resources