adding a new div after another one - javascript

I am trying to add a new div right after a div with the class of dtext01 but its not working.
Here is what the div looks like with the class <div class="dtext01"></div> and I would like the final code to look like this <div class="dtext01"></div><div id="rewards">Testing!!!</div>
Here is the code I have tried with no success.
<script type="text/javascript">
var stickyNode = document.createElement("div");
stickyNode.innerHTML = 'Testing!!!';
stickyNode.id = "rewards";
var referenceNode = document.getElementByClass("dtext01");
referenceNode.parentNode.insertBefore(stickyNode, referenceNode);
</script>

There is no document.getElementByClass(). There are document.getElementsByClassName() and querySelectorAll() which can be used for fetching elements by className, but they are not standard across browsers.
You can always import a cross browser getElementsByClassName from a reliable source, such as this one, or write your own - or just use IDs instead of classes if you have a choice.

The function you are looking for is document.getElementsByClassName (note the plural on Elements). It is a fairly recent addition to the HTMLElement interface, so you should test for it and provide a fallback if it isn't supported.
To append your div just after the first node returned, use:
var referenceNode;
if (document.getElementsByClassName) {
referenceNode = document.getElementsByClassName("dtext01")[0];
} else {
// fallback to some other function
}
// Make sure you got a node before trying to call methods on it
if (referenceNode) {
referenceNode.parentNode.insertBefore(stickyNode, referenceNode);
}

Related

Including a javascript function in a custom joomla module

I have a working codepen that uses some javascript
https://codepen.io/cbold/pen/jOWONKO
I am struggling to understand the correct method/syntax for including the javascript function with my custom Joomla module.
I have read the official documentation but it does not make it any clearer for me
https://docs.joomla.org/J3.x:Adding_JavaScript_and_CSS_to_the_page
I have also looked at several other similar questions posted on Stackoverflow, but I do not understand any of the examples/answers enough to apply them to my module.
I have tried to include the function as a separate file, and invoke it with my mod_mymodule.php :
$document = JFactory::getDocument();
$document->addScript(JURI::root(true)."modules/mod_mymodule/js/ mod_mymodule.js");
This is the javascript in mod_mymodule.js:
function clickHandler(target) {
// Get the element that should be selected
const elem = document.querySelector(target);
// There were no elements to be selected
if (!elem) return;
// Get the old selected element (if any)
const prevElem = document.querySelector('.selected');
if (prevElem) {
// If there was a previously selected element, it isn't anymore
prevElem.classList.remove('selected');
}
// Make the new element selected
elem.classList.add('selected');
}
The function does not occur.
I have tried both document.querySelector(target); and document.querySelector('#target');
I have also tried including the function at the end of my module’s default.php
<script type="application/javascript">
function clickHandler(target) {
// Get the element that should be selected
const elem = document.querySelector(target);
// There were no elements to be selected
if (!elem) return;
// Get the old selected element (if any)
const prevElem = document.querySelector('.selected');
if (prevElem) {
// If there was a previously selected element, it isn't anymore
prevElem.classList.remove('selected');
}
// Make the new element selected
elem.classList.add('selected');
}
</script>
But no luck.
Again I have tried both document.querySelector(target); and document.querySelector('#target');
I am pretty certain my <script> is wrong, but I don’t know enough about javascript – specifically the proper syntax required by Joomla – in order to make it work directly from my module.php.
Any help is greatly appreciated.
This ended up working for my needs, a short script in the module's default.php
<script>
jQuery('.target').click(function(){
var id = jQuery(this).attr('id');
jQuery('body').find('.selected').removeClass('selected');
jQuery('#target'+id).addClass('selected');
});
</script>

Reduce the DOM search frequency in Javascript

I'm in the process of getting rid of Jquery from a small project and re-writing the script with vanilla js. In the current code there's a jquery implementation to search a DOM element and then use jquery 'find'to search specific elements within the element.
var ImageCapture ={
cacheDom : function(){
this.form = $('#drawingBoard');
this.saveBtn = this.form.find('#saveBtn');
this.image = this.form.find('#image');
this.results = this.form.find('#results');
}
}
I've converted the above Jquery code into vanilla js like below.
var ImageCapture ={
cacheDom: function () {
this.form = document.getElementById('drawingBoard');
this.saveBtn = this.form.querySelector('#saveBtn');
this.image = this.form.querySelector('#image');
this.results = this.form.querySelector('#results');
}
}
The new implementation seem to be working fine but I wanted to be sure if it's the correct way of replacing the Jquery implementation using vanilla JS?
Thanks in advance.
I've made two jsfiddles to show you a subtle difference in behavior between plain js querySelectorAll and jQuery selectors. You would naturally expect them to behave the same but they do not.
Here is the plain js version: https://jsfiddle.net/a81e2do3/
Here is jQuery: https://jsfiddle.net/a81e2do3/1/
In short, if you have this html:
div#a > div#b > div#c
if you have a plain JS element node object of #b, you can do b.querySelector('#a #c') and successfully select div#c, but you cannot do that in jQuery (which imo makes more sense the jQuery way).

Efficient OOP way to generate DOM elements dynamically with JavaScript?

I'm tinkering with writing a more efficient methodology in the creation of dynamically generated DOM elements via JavaScript. This is something I intend to add into my own JS framework later on. Looking for other OOP devs that could help better refine what I do have.
Here's a link to the working CodePen:
http://codepen.io/DaneTheory/pen/yeLvmm/
Here's the JS:
function CreateDOMEl() {};
CreateDOMEl.prototype.uiFrag = document.createDocumentFragment();
CreateDOMEl.prototype.elParent = function(elParent, index) {
this.elParent = document.getElementsByTagName(elParent)[index];
}
CreateDOMEl.prototype.elType = function(type) {
newEl = document.createElement(type);
this.uiFrag.appendChild(newEl);
}
CreateDOMEl.prototype.elContent = function(elContent) {
this.elContent = elContent;
newEl.textContent = elContent;
}
CreateDOMEl.prototype.buildEl = function() {
this.elParent.appendChild(this.uiFrag);
}
var div = new CreateDOMEl();
div.elParent('body', 0);
div.elType('DIV');
div.elContent('OK');
div.buildEl();
console.log(div);
var bttn = new CreateDOMEl();
bttn.elParent('body', 0);
bttn.elType('BUTTON');
bttn.elContent('SUBMIT');
bttn.buildEl();
console.log(bttn);
And some CSS to get elements to appear on page:
div {
width:100px;
height:100px;
border: 1px solid red;
}
My thoughts:
For performance, using the prototype to build methods versus placing all the logic in the constructor.
Rather than directly appending elements to the page, append to a single Document Fragment. Once the element is built out as a Doc Frag, appending the Doc Frag to to the DOM. I like this method for performance, but would like to improve upon it. Any useful implementations of requestnimationFrame, or using range and other versions of the document fragment method?
Silly, but I think for debugging it'd be nice to see the generated Element type within the Object property's on console log. As of right now, console logging a created element will show the elements parent and text content. It'd be great to show the elements type as well.
Creating more than one element at a time is another piece of functionality I'd like to offer as an option. For instance, creating a div element creates one div element. What's a good way to add another optional method to create multiple instances of div's.
div.elType('DIV');
// After calling the elType method, do something like this:
div.elCount(20);
// This would create 20 of the same divs
Lastly, a nice clean way to optionally add attributes (i.e: classes, an ID, value, a placeholder, custom attributes, data-* attributes, etc.). I've got a nice helper function I use that adds multiple attributes to an element in an object literal syntax looking way. Adding this as a method of the constructor would be ideal. Here's that function:
function setAttributes(el, attrs) {
for(var key in attrs) {
el.setAttribute(key, attrs[key]);
}
}
// A use case using the above
// function would be:
var anInputElement = document.createElement("TEXTAREA");
setAttributes(anInputElement, {
"type": "text",
"id": "awesomeID",
"name": "coolName",
"placeholder": "Hey I'm some placeholder example text",
"class": "awesome"
});
// Which creates the following HTML snippet:
<textarea type="text" id="awesomeID" name="coolName" placeholder="Hey I'm some placeholder example text" class="awesome">
As a side note, realizing now that the above helper function needs rewritten so that multiple classes could be created.
Respectfully, I believe you may be overthinking it. Just use the tools available in JavaScript and get 'er done. In terms of performance, computers are so fast at running your JavaScript that you (and me) are unable to perceive, or even comprehend, the speed. Here's how I add a link to an MDL nav menu, for example. It's just vanilla JS. Don't forget to add event listeners.
function navMenuAdd(type,text){
var newAnchor = doc.createElement("anchor");
newAnchor.classList.add('mdl-navigation__link');
newAnchor.classList.add(type);
newAnchor.href = "javascript:void(0)";
var anchorContent = doc.createTextNode(text);
newAnchor.appendChild(anchorContent);
newAnchor.addEventListener('click', navMenuClickHandler, false);
//newAnchor.style.display = 'none';
if (type === 'Thingy A'){
//insertAfter(newAnchor, navMenuCredentials);
navMenuCredentialsPanel.appendChild(newAnchor);
} else if (type === 'Thingy B'){
//insertAfter(newAnchor, navMenuDevices);
navMenuDevicesPanel.appendChild(newAnchor);
}
}

How to alter DOM with xmldom by XPath in node.js?

I am trying to alter a DOM structure in node.js. I can load the XML string and alter it with the native methods in xmldom (https://github.com/jindw/xmldom), but when I load XPath (https://github.com/goto100/xpath) and try to alter the DOM via that selector, it does not work.
Is there another way to do this out there? The requirements are:
Must work both in the browser and server side (pure js?)
Cannot use eval or other code execution stuff (for security)
Example code to show how I am trying today below, maybe I simply miss something basic?
var xpath = require('xpath'),
dom = require('xmldom').DOMParser;
var xml = '<!DOCTYPE html><html><head><title>blah</title></head><body id="test">blubb</body></html>';
var doc = new dom().parseFromString(xml);
var bodyByXpath = xpath.select('//*[#id = "test"]', doc);
var bodyById = doc.getElementById('test');
var h1 = doc.createElement('h1').appendChild(doc.createTextNode('title'));
// Works fine :)
bodyById.appendChild(h1);
// Does not work :(
bodyByXpath.appendChild(h1);
console.log(doc.toString());
bodyByXpath is not a single node. The fourth parameter to select, if true, will tell it to only return the first node; otherwise, it's a list.
As aredridel states, .select() will return an array by default when you are selecting nodes. So you would need to obtain your node from that array.
You can also use .select1() if you only want to select a single node:
var bodyByXpath = xpath.select1('//*[#id = "test"]', doc);

TypeError: undefined is not a function jQuery

I'm new to jQuery and I can get it to sometimes work, however, for some reason, when I try to call a function, it gives me the title error, but if I do it in developer tools, it works fine.
http://jsfiddle.net/otanan/pmzzLo3e/#&togetherjs=AezijhfBrj
It seems to work fine when retrieving the classes from the DOM, but not when I call a function such as
.click(function() {});
Here's the code:
var downloads = $(".info"),
className = "info_clicked";
for(var i in downloads)
{
downloads[i].click(function()
{
if(!this.hasClass(className))
this.addClass(className);
else
this.removeClass(className);
});
}
When you access a jQuery collection as an array, it returns the DOM elements, not jQuery objects. You should use .each() rather than for (i in downloads):
downloads.each(function() {
$(this).click(function() {
if (!$(this).hasClass(className)) {
$(this).addClass(className);
} else {
$(this).removeClass(className);
}
});
});
You could also simplify the whole thing to:
downloads.click(function() {
$(this).toggleClass(className);
});
Most jQuery methods automatically iterate over all the elements in a collection if it makes sense to do so (the notable exceptions are methods that return information from the element, like .text() or .val() -- they just use the first element). So you generally only have to iterate explicitly if you need to do different things for each element. This is one of the great conveniences of using jQuery rather than plain JS: you rarely have to write explicit iterations.
I think the issue is that you're attempting to call a jQuery function on an object that is no longer a jQuery object.
For example you're saying $(".info"). Which retrieves a single jQuery object. As soon as you index that object downloads[i] it is no longer a jQuery object, it is a plain HTML element and does not have a click function available.
What you really need to do is get the jQuery object for the indexed item:
var downloads = $(".info"),
className = "info_clicked";
for(var i = 0; i < downloads.length; i++)
{
$(downloads[i]).click(function()
{
if(!this.hasClass(className))
this.addClass(className);
else
this.removeClass(className);
});
}
try it:
$(downloads[i]).click(function(){ //...

Categories