Create element inside another based on id - javascript

rigth now I have this code to draw some divs (based on some logic I'll have parent and childs.
array.forEach(async (a, b) => {
var currentDiv = 0;
let divHtml;
if (b === 0) {
//This should be the first parent
divHtml = document.createElement('div');
divHtml.id = 'someID' + currentDiv;
} else if (previousDiv != currentDiv) {
// This should be used for next parents based on the previousDiv & currentDiv logic
divHtml = document.createElement('div');
divHtml.id = 'someID' + currentDiv;
} else {
// This should be used only for childs. I want to create another div but inside the parent that I have stored into currentDiv.
divHtml = document.getElementById('someID' + currentDiv);
divHtml.id = 'someChildID' + currentDiv;
}
// Some more code below but what it's important is this (I continue using the divHtml in a lot of places on my code):
divHtml.setAttribute('someData', someDataAttribute);
});
So, my question is: if there is a way to get the parentDiv and draw inside the X childs elements and how can I do it? I tried with this:
divHtml = document.createElement('div').appendTo($('#someID' + currentDiv));
But I'm getting the .appendTo() is not a function error message.

.appendTo() is a jQuery method, it seems you are using plain javascript, maybe you want to use append or appendChild

Related

$(selector, element) Native JS alternative

Hi I'm trying to remove all jQuery from my platform one line at a time.
But I'm having some trouble finding a replacement for this
$('[data-attribute="value"]', GenericHTMLElement);
I was hoping it would be something simple like
var div = document.createElement('div');
div.innerHTML = '<div><span data-attribute="value"></span><span data-something-else="1000"></span></div>';
var b = div.childNodes;
var a = b.querySelector('[data-attribute="value"]');
But that's not working either. Does have any suggestions for me?
As commented,
childNodes will give you a list of elements. This list will not have querySelector. If you loop over nodes, you should be able to get it though. But, my suggestion is just do div.querySelector(...)
To be specific, it will be of type NodeList. This is a collection of nodes. So you cannot run querySelector on it. You can either loop over all nodes and do querySelector on them or just so this operation on parent div.
var div = document.createElement('div');
div.innerHTML = '<div><span data-attribute="value">Dummy Text</span><span data-something-else="1000"></span></div>';
var b = div.childNodes;
console.log('Type of childNodes is: ', Object.prototype.toString.call(b))
// getting element using loop over childNodes
for(var i = 0; i<b.length; i++) {
var el = b[i].querySelector('[data-attribute="value"]');
el && console.log(el.textContent)
}
// getting element using parent elenent.
var el1 = div.querySelector('[data-attribute="value"]');
console.log(el1.textContent)
First you need to understand what the first code does. It searches for given selector, limiting it to HTMLElementObject scope. Understanding that we can try to do something similar.
From MSDN example, he is using body element:
var el = document.body.querySelector("style[type='text/css'], style:not([type])");
They have this example with data-attributes, take a look please.
The reason your attempt isn't working is that you're trying to call querySelector on a NodeList, which doesn't have a querySelector method.
If you try it on a single element, it works fine:
function mySelect(selector, el) {
return el.querySelector(selector);
}
var div = document.createElement('div');
div.innerHTML = '<div><span data-attribute="value"></span><span data-something-else="1000"></span></div>';
var b = div.childNodes[0];
console.log(mySelect('[data-attribute="value"]', b));
But this makes it so that mySelect(selector, el) is nothing more than an alias for el.querySelector(selector).
Presumably, you'd want to be able to evaluate a selector on multiple elements at once, and return multiple results, like jQuery does. In that case, you can do so by making some adjustments:
function flatMap(values, f) {
return Array.prototype.concat.apply([], values.map(f));
}
function mySelect(selector, els) {
return flatMap(els.length ? Array.from(els) : [els], function (el) {
return Array.from(el.querySelectorAll(selector));
});
}
var div = document.createElement('div');
div.innerHTML = '<div><span data-attribute="value">span 1</span><span data-something-else="1000"></span></div><div><span data-attribute="value">span 2</span></div>';
console.log(mySelect('[data-attribute="value"]', div.childNodes));
console.log(mySelect('[data-attribute="value"]', div.childNodes[0]));

search for element within element by tagname

After being stuck for a few hours on this problem, i think it is time for call for help on this.
Situation
I have a XML file which i need to filter and group. I've managed to filter it with the :Contains part. I've also determined the nodes on which i need to group (the getGroups function gives those back to me). Now i want to create a new XML with the filtered values and grouped by the returned keys.
Code
var XMLElement = document.createElement("DataElementsCalc");
jQuery(xml).find("DataElements " + topNodes + filter).each( function() {
var dataSetTemp = this.parentNode;
if(calculation1 != "")
{
var groupKeys = getGroups(dataSetTemp,calculation1);
var tempXML = XMLElement;
jQuery(groupKeys).each(function (key,value) {
var tempValue = 'a' + value.toLowerCase().replace(/\W/g, '');
if(tempXML.getElementsByTagName(tempValue).length > 0)
{
tempXML = tempXML.getElementsByTagName(tempValue);
}
else
{
var Node = document.createElement(tempValue);
tempXML.appendChild(Node);
tempXML = Node;
}
});
var Node = document.createElement("InfoSet");
var x = dataSetTemp.childNodes;
for (i=0; i < x.length; i++)
{
if(x[i].nodeType == 1)
{
var tempElement = document.createElement(x[i].nodeName);
tempElement.innerHTML = x[i].childNodes[0].nodeValue;
Node.appendChild(tempElement);
}
}
tempXML.appendChild(Node);
}
});
Explanation
As said in the situation, i already filtered the XML and have the groupNames from the getGroups function. There are a few other things i need to explain for this code:
tempValue is being build as a a + value.toLowerCase().replace(/\W/g, '');. This is being done because i possible get dates into the groupKeys. This way the node name is getting a working name (i received errors on other ways).
I want to create a new XML which is leveled by the groups. If a group already exists, i want to create a new element in it, not get a new group with the same name. (my problem at the moment).
Problem
As mentioned above, the groups aren't checked properly. Firstly: tempXML.getElementsByTagName(tempValue).length returns the error that the function tempXML.getElementsByTagName does not exists. Secondly: If i change this to document.getElemetsByTagName I get a lot of the same nodes in my XML file.
Effect
The grouping effect doesn't work as it should. I get OR an error, OR a lot of the same nodes in my DataElementsCalc.
Questions
How can i solve this? How do create nodes beneath specific nodes (for if there is a group A beneath group 1 as well as beneath group 2)?
Tried
Change tempXML to document on different places (all getElementsByTagName, at the same time or not). Looked for another way to create a XML which is easier to handle (haven't found one, yet)
As mentioned by myself in the comments of the question:
I also don't see anything in the source code for this (maybe this is the reason why it doesn't work??)
I tried to place the XMLElement into an existing element on my webpage (like this:
var XMLElement = document.createElement("DataElementsCalc");
jQuery('.basicData').append(XMLElement);
in which basicData is a class of an existing element).
Now i do get a list of all elements ordered on the groups i wanted.
Final version
var XMLElement = jQuery("<DataElementsCalc/>");
jQuery('.basicData').append(XMLElement);
jQuery(xml).find("DataElements " + topNodes + filter).each( function()
{
aantalElementsTotal++;
var dataSetTemp = this.parentNode;
if(calculation1 != "")
{
var groupKeys = getGroups(dataSetTemp,calculation1);
var tempXML = XMLElement;
var groupId = '';
jQuery(groupKeys).each(function (key,value) {
var tempValue = 'a' + value.toLowerCase().replace(/\W/g, '');
groupId += 'a' + value.toLowerCase().replace(/\W/g, '');
if(jQuery("#" + groupId).length > 0)
{
tempXML = jQuery("#" + groupId);
}
else
{
var Node = jQuery("<"+tempValue+"/>");
jQuery(Node).attr('id', groupId);
jQuery(tempXML).append(Node);
tempXML = Node;
}
});
var Node = jQuery("<InfoSet/>");
var x = dataSetTemp.childNodes;
for (i=0; i < x.length; i++)
{
if(x[i].nodeType == 1)
{
var tempElement = jQuery("<"+x[i].nodeName+"/>");
jQuery(tempElement).text(x[i].childNodes[0].nodeValue);
jQuery(Node).append(tempElement);
}
}
jQuery(tempXML).append(Node);
}
});

jQuery append element if it doesn't exist, otherwise replace

Here's a short piece of code:
var $el = $("#something").find(".test");
if (!$el.length) {
$("#something").append('<div class="test">somecontent</div>');
} else {
$el.replaceWith('<div class="test">somenewcontent</div>');
}
I couldn't find a method appendOrReplaceWith or anything similar.
Any ideas how can I make it shorter?
I believe that:
$("#something").appendOrReplace('<div class="test">sometext</div>');
would be much easier to read, but no such method is available yet.
Just remove it first then append.
$(".test").remove();
$("#something").append('<div class="test">somecontent</div>');
Mandatory vanilla answer. It may not be shorter, but it's faster.
Get the element, grab all subelements with the class "test", create your div, check the subelements length, and if length is truthy, set the innerHTML to the div. Else, append it.
var el = document.getElementById("something");
var subel = el.getElementsByClassName("test");
var div = document.createElement("div");
div.className = "test"
if (subel.length) {
div.textContent = "somenewcontent";
while(el.hasChildNodes()) el.removeChild(el.lastChild); //remove child nodes
el.appendChild(div);
} else {
div.textContent = "somecontent";
el.appendChild(div);
}
Adding a method like findOrAppend to jQuery could be useful:
$.fn.findOrAppend = function(selector, content) {
var elements = this.find(selector);
return elements.length ? elements : $(content).appendTo(this);
}
Then you can chain text, replaceWith, empty etc. as needed:
$("#something")
.findOrAppend(".test", "<div class='test'>")
.text("newcontent");
First of all you should cache your selectors:
var $som = $('#something');
var $ele = $(".test",$som);
var newHtml = '<div class="test">somecontent</div>';
if (!$el[0]) $som.append( newHtml );
else $ele.replaceWith( newHtml );
but you already did it really fine, (beside not caching repeated selectors), and me, trying to make it smaller could be a**-kicked for not using {} for my if and else :)
I would do this
var $s = $("#something"), $t = $s.find(".test"), c = 'New content';
( $t[0] ? $t:$s)[( $t[0] ? 'html':'append')](( $t[0] ? c :$('<div>',{class:'test'}).append(c)));

Replacing all urls in a div

I am trying to write javascript code to find all the urls inside a div. Now this would be pretty easy if all the urls within the div were separated by spaces in which case I can just do a regex on what's inside the div to find them. However, the urls within this outer div may be in sub divs (or any other html tag) and I want to consider the subdivs as separators as well (and I don't want to get rid of these subdivs). To give an example, in the following I want to find www.foo.com and www.bar.com within the div with id "outer":
<div id="outer"><div>www.foo.com</div>www.bar.com</div>
What would be a good way of doing this?
You can apply a recursive call to all non-text child nodes.
function replaceWwwInNodes(node) {
//text node
if (node.nodeType === 3) {
node.textContent = node.textContent.replace(/* ??? */)
}
else {
Array.prototype.forEach.call(node.childNodes, function (elem) {
replaceWwwInNodes(elem);
});
}
}
replaceWwwInNodes(document.getElementById('outer'));
http://jsfiddle.net/UDX5V/
Try to use this sample http://jsfiddle.net/iklementiev/TaCx9/1/
var data = document.getElementById("outer").innerText;
var myRe = /www\.[0-9a-z-]+\.[a-z]{2,4}/igm;
var matches= data.match(myRe)
for (var i = 0; i < matches.length; i++) {
alert('match: ' + matches[i]);
}
this help to find all urls.
try this
var expression = /[-a-zA-Z0-9#:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9#:%_\+.~#?&//=]*)?/gi;
var regex = new RegExp(expression);
var regContent = $("#outer").html();
var newContent = regContent;
if(regContent.match(regex))
{
var textContent = regContent.match(regex);
for(var i=0;i<regContent.match(regex).length;i++)
{
newContent = newContent.replace(new RegExp(regContent.match(regex)[i], "g"), "test");
}
$("#outer").html(newContent);
}
this will get all url content and replace it as "test".

JavaScript: Add elements in textNode

I want to add an element to a textNode. For example: I have a function that search for a string within element's textNode. When I find it, I want to replace with a HTML element. Is there some standard for that?
Thank you.
You can't just replace the string, you'll have to replace the entire TextNode element, since TextNode elements can't contain child elements in the DOM.
So, when you find your text node, generate your replacement element, then replace the text node with a function similar to:
function ReplaceNode(textNode, eNode) {
var pNode = textNode.parentNode;
pNode.replaceChild(textNode, eNode);
}
For what it appears you want to do, you will have to break apart the current Text Node into two new Text Nodes and a new HTML element. Here's some sample code to point you hopefully in the right direction:
function DecorateText(str) {
var e = document.createElement("span");
e.style.color = "#ff0000";
e.appendChild(document.createTextNode(str));
return e;
}
function SearchAndReplaceElement(elem) {
for(var i = elem.childNodes.length; i--;) {
var childNode = elem.childNodes[i];
if(childNode.nodeType == 3) { // 3 => a Text Node
var strSrc = childNode.nodeValue; // for Text Nodes, the nodeValue property contains the text
var strSearch = "Special String";
var pos = strSrc.indexOf(strSearch);
if(pos >= 0) {
var fragment = document.createDocumentFragment();
if(pos > 0)
fragment.appendChild(document.createTextNode(strSrc.substr(0, pos)));
fragment.appendChild(DecorateText(strSearch));
if((pos + strSearch.length + 1) < strSrc.length)
fragment.appendChild(document.createTextNode(strSrc.substr(pos + strSearch.length + 1)));
elem.replaceChild(fragment, childNode);
}
}
}
}
Maybe jQuery would have made this easier, but it's good to understand why all of this stuff works the way it does.

Categories

Resources