Can you target new instances of an object uniquely without passing them an id as a parameter?
If you create new objects from a constructor and each instance has access to some html (presentation) stored as a variable in the constructor, when new instances of the object are created and html is output from the presentation variable, how do you target each of these instances in a unique way? How could you style one instance differently from the other?
function MyObj() {
this.content = "<div class = 'someclass'>Some text </div>";
}
var newObj1 = new MyObj();
console.log(newObj1.content); //outputs Some text
var newObj2 = new MyObj();
console.log(newObj2.content); //outputs Some text
If you wanted to target the css of all new classes you could use:
var target1 = $('.someclass').css('color,'orange');
But how to target one differently from the other?
You can pass in something that is unique to acknowledge each object. Below I pass in a name to be added to the elements class attribute.
Note if you are using the CSS elsewhere then this is fine, but if it's just used once then why not add an id to distinguish the areas uniquely. That is, that is what an id is meant for.
function MyObj(name) {
if(name != undefined) {
this.content = "<div class = 'default " + name + "'>Some text </div>";
} else {
this.content = "<div class = 'default'>Some text </div>";
}
}
var newObj1 = new MyObj('blue-rows');
console.log(newObj1.content); //outputs Some text
var newObj2 = new MyObj('orange-rows');
console.log(newObj2.content); //outputs Some text
var newObj3 = new MyObj();
console.log(newObj3.content); //outputs Some text
var container = document.getElementById('container');
container.innerHTML += newObj1.content;
container.innerHTML += newObj2.content;
container.innerHTML += newObj3.content;
.default {
color: red;
}
.blue-rows {
color: blue;
}
.orange-rows {
color: orange;
}
<div id="container">
</div>
That depends on how you'd like to target the other instance. One option is to use the :nth-child, :first-child, or :last-child selectors. As an example:
$('.someclass:nth-child(even)').css('color','orange');
$('.someclass:nth-child(odd)').css('color','blue');
$('.someclass:nth-child(1)').css('color','green');
$('.someclass:first-child').css('color','red');
Related
I have some trouble with appending a new div to an existing parent that I just created. After creation of the parent I check it's existence. But when I want to append the child to it after selecting the parent via it's id I get an error. What do I do wrong?
var uiDiv = document.createElement("div");
uiDiv.id = "f_jsonuiDiv";
uiDiv.innerHTML = "jsonUI controls";
console.log("uiDiv");
console.dir(uiDiv); //shows uiDiv object
//select container div
const parentId = "f_jsonuiDiv"; //which is the id of the newly created container div
console.log("parentId: ",parentId);
var parElement = document.getElementById(parentId);
console.log("parElement: ");
console.dir(parElement); //says: null !
//create directly
//const newDiv = parElement.createElement("div"); //throws error as parElement does not exist ......
//create first, then append
const newDiv = document.createElement("div");
newDiv.innerHTML = "NEW DIV";
//parElement.appendChild(newDiv); //throws error as parElement does not exist ......
uiDiv.appendChild(newDiv); //does not throw an error ```
Seems like you need to add uiDiv to body (or any other parent) first, in order to get it with getElementById
document.body.appendChild(uiDiv);
// This should be valid now
const parElement = document.getElementById(parentId);
You need to put the script after the body let the DOM be created .
Or warp your code with
window.addEventListener('DOMContentLoaded', (event) => { //put your code here });
it will run after the page is loaded
A would advise to use insertAdjacentElement and insertAdjacentHTML. It makes your life easier.
// insertAdjacentElement returns the newly created element
const uiDiv = document.body.insertAdjacentElement(`beforeend`,
Object.assign(document.createElement("div"), {
id: "f_jsonuiDiv",
innerHTML: "jsonUI controls" })
);
// so now you can inject it wit some html
uiDiv.insertAdjacentHTML(`beforeend`,`<div>HI, I am the NEW DIV in town</div>`);
#f_jsonuiDiv div {
color: red;
padding: 2px 1em;
border: 1px solid #AAA;
max-width: 400px;
text-align: center;
}
I am getting the content of a div from my page and storing it to the local storage (the content of the div are variable, dependent of the user input)
var content= document.getElementById('tobestoreddiv').innerHTML;//get the content
localStorage.setItem("content", content);// store the content
I want to remove the function from some of the divs inside the content div. Some of them have onclick events and so on..
I have tried using .replace() to remove some of the tags and functions as follows:
var changedinnerhtml = localStorage.getItem("content");
changedinnerhtml = changedinnerhtml.replace('autoplay="" loop=""', 'autoplay loop muted');//for videos, idk why the tags are set to =""
changedinnerhtml = changedinnerhtml.replace('contenteditable="true"', ''); // as an example for tags
changedinnerhtml = changedinnerhtml.replace('onclick="function();"', ''); // as an example for functions
document.body.innerHTML = changedinnerhtml; // this is displaying on another page
But this method isn't working is there another way to remove the functions and tags?
try it:
function replaceAll(source, search, replace, ignoreCase) {
//SCAPE SPECIAL CHARACTERES.
var search1 = this.regExpEscapeSpecialCharacters(search);
//IGNORE CASE SENSIVITY.
var ignore = (ignoreCase) ? "gi" : "g";
var result = source.replace(new RegExp(search1, ignore), replace);
return result;
}
var changedinnerhtml = localStorage.getItem("content");
changedinnerhtml = replaceAll(changedinnerhtml, 'autoplay="" loop=""', 'autoplay loop muted', true);//for videos, idk why the tags are set to =""
changedinnerhtml = replaceAll(changedinnerhtml, 'contenteditable="true"', '', true); // as an example for tags
changedinnerhtml = replaceAll(changedinnerhtml, 'onclick="function();"', '', true); // as an example for functions
document.body.innerHTML = changedinnerhtml; // this is displaying on another page
I would be more defensive about which attributes you do want to have on your element. Create a list of attributes, note that empty values (muted="") are the same as having no values at all muted, so don't worry about removing those.
const localStorageResult = `<div class='some-class' contenteditable="true" autoplay="" loop="" muted="" some-other-attribute onclick='function() { alert("Click"); }'>Hello world</div>`;
const copyAttributes = [
'class',
'autoplay',
'loop',
'muted'
];
// Create a dummy element
var containerElement = document.createElement( 'div' );
// This parses the element, so it becomes valid HTML
containerElement.innerHTML = localStorageResult;
const storedElement = containerElement.firstElementChild;
const elementType = storedElement.tagName;
const newElement = document.createElement(elementType);
copyAttributes
.filter((attribute) => storedElement.hasAttribute(attribute))
.forEach((attribute) => {
newElement.setAttribute(attribute, storedElement.getAttribute(attribute));
});
document.body.appendChild(newElement);
.some-class {
background: red;
width: 100px;
height: 100px;
}
I'd like to use pure JS to check if some String, the textareas .innerHTML = newContent below, contains some tag (h1in my case) at the beginning (=as first child). What would be the best way to do this?
Thanks!
function submitNewSectionContent(e) {
for (var i = 0; i < sections.length; i++)
let newHeading = document.getElementById('edit-title').value;
/* edit-title is text-input*/
let newContent = document.getElementById('edit-sectionText').innerHTML;
/* edit-sectionText is textarea */
if (newContent.indexOf('<h1>') > -1 && newContent.indexOf('<h1>') < 10) { /* <h1> is at beginning so replace with newHeading */
let toberemoved = newContent.match('<h1>.*<\/h1>');
newContent = newContent.replace(toberemoved[0], '').trim();
sections[i].innerHTML = '<h1>'+newHeading+'</h1>' + sections[i].innerHTML;
} else { /* newContent has no h1 as first child, so add h1 from newHeading */
sections[i].innerHTML = '<h1>'+newHeading+'</h1>' + newContent;
}
}
}
Problem with Regular expressions is they do not really work well with HTML. So Your best bet is to convert it to a DOM fragment and do the manipulations and convert it back. Only issue with this method really is you can lose formatting. There are libraries out there that can pretty print HTML.
function updateHeadline(txt) {
const ta = document.querySelector("textarea");
const data = ta.value; // read value, not innerHTML
const temp = document.createElement('div'); // temp div to hold html
temp.innerHTML = data; // set the html to the temp element
let firstChild = temp.firstElementChild // look at the dom
if (!firstChild || firstChild.tagName!=="H1") { // see if we have an h1
firstChild = document.createElement("h1") // if not create one
temp.prepend(firstChild) // add it to the front
}
firstChild.innerHTML = txt // set the new text of the h1
ta.value = temp.innerHTML // put the content back into the textarea
}
const btn = document.querySelector("button");
btn.addEventListener("click", function (e) {
e.preventDefault()
updateHeadline(document.querySelector("#text").value)
})
textarea {
width: 300px;
height: 200px;
}
<textarea>
<p>Some other text</p>
<p>Some more text</p>
</textarea>
<input value="foo" id="text"/>
<button>Set</button>
You could use regex like so, (updated based on comment)
if( /^\s*<h1>/gi.test(stringToTest) ) {
//logic here
}
It checks if the stringToTest begins with ^ tag
See here : https://regex101.com/r/vSo4sL/1
convert to dom, and parse dom
this portion of code makes it possible to treat a chain to retrieve titles placed in the H1 tag and (on the fly) treat the string of characters.
It's easily expandable for future processing : or tag processing or other ...!
commented code
<html>
<script>
var s="<H1>Hey Title</H1>\n Hello,\n other title <H1>Green!</H1>\n Ipsum dolore sit...";
console.log(s);
console.log("-------------------------");
var partialDoc = document.createElement( 'html' );
partialDoc.innerHTML = s;
var parsed='';
var titles=[];
treatment(partialDoc);
console.log("\n-------------------------\n");
console.log("parsed",parsed);
console.log("\n-------------------------\n");
console.log("s var contains "+titles.length+ " H1 tag");
console.log("titles "+titles);
function treatment(root) {
var child = root.firstChild;
while (child) {
// child.nodeName = H1 | H2 | P etc...
// child.nodeType = 1
// catch H1
if (child.nodeName=='H1') {
// append your title,
parsed+=" [H1 FOUND content= {"+child.innerText+"} H1])";
// or
// parsed+="<H1>"+child.innerText+"<H1>";
// add your own process here
// add this title in array
// or what you want...
titles.push(child.innerText);
// next part of document
child = child.nextSibling;
continue;
}
// capture other text than H1
if (child.nodeType==3) { // Node Type Text
parsed+=child.nodeValue;
}
if (child.nodeType==1) { // Node Type ELEMENT, : sub nodes...
treatment(child);
}
// continue the rest of doc
child = child.nextSibling;
}
}
</script>
</html>
One way you could do it is: Node.firstElementChild which will avoid giving child node as #text for white-spaces and Node.nodeName
let firstChild = document.getElementById('edit-sectionText').firstElementChild;
if(firstChild.nodeName === "H1"){
firstChild.innerHTML = "Replacement Value"
}
Note & Update: The earlier api that I had suggested Node.firstChild will not prevent white-spaces which gives #text node and comments as #comment node.
2nd Way: Node.children and picking the first child out of it should have a similar result to Node.firstElementChild.
let elem = document.getElementById('edit-sectionText');
if(elem){
let firstChild = elem.children[0];
}
Update based on comments: Using Dom Parser Interface
The interface allows to parse XML or HTML source from a string based on the mime type provided for its method parseFromString(string, mimeType)
It will give the top level #document node with parsed HTML from the string where if exists <h1> or <H1> at the beginning would be the first child of body and subsequently can be tested via tagName property.
Note: Takes care of preceding HTML comments and spaces at the beginning but a caveat is doesn't check fully closed tags ex: var s = \t <h1>I am a heading <h1> here the <h1> was never closed and in the result will two fully formed headings at the body with content : I am a heading and ""
let textAreaString = document.getElementById("edit-sectionText").value;
const domParser = new DOMParser();
const parsedDoc = domParser.parseFromString(textAreaString, "text/html");
if (parsedDoc.body.firstElementChild.tagName === "H1") {
//yes it starts with <h1> or <H1>
}
I'm writing a javascript program that gets the input in any of the below forms.
"Here is the result \"google\", and \"yahoo\""
or
"Here is a plain result"
and this is stored in a variable say X. and I want to create an anchor tag when ever I come across an anchor tag. I know that a href will by default create an anchor tag but in my case the result is rendered as a text, here is my code that I've tried so far.
var newLink = document.createElement('a');
newLink.href = 'http://google.com';
newLink.innerHTML = 'My anchor';
if (message) {
var x = message;
console.log(x.includes("href"));
if (!x.includes("href")) {
responsePara.appendChild(document.createTextNode(message));
responsePara.appendChild(document.createElement('br'));
} else {
//responsePara.appendChild(document.createTextNode(message));
responsePara.appendChild(newLink);
responsePara.appendChild(document.createElement('br'));
}
}
the output that I'm expecting is in case 1
<p> Here is the result "google", and "yahoo"</p>
in case 2
<p>Here is a plain result</p>
please let me know on how can I do this.
Note I'm using only js, no jquery
I can't see your problem, it should be really easy to implement this, right?
All you need to parse is the input that is coming to HTML. within another element (in your case p element)
UPDATE
I have updated this question, so you can modify (or create if there is not ref) an existing element with not parsed a element or with plain text.
function createOrUpdateCompositeLink(input, ref) {
if (ref) {
var isLinkText = input.match(/href/g);
var elementChild;
if (isLinkText) {
elementChild = document.createElement('span');
elementChild.innerHTML = input;
} else {
elementChild = document.createTextNode(input);
}
ref.appendChild(elementChild);
return ref;
} else {
var element = document.createElement('p');
element.innerHTML = input;
return element;
}
}
/* USAGE */
var message;
var element;
message = "Here is the result ";
message1 = "google\"";
message2 = " something plain text ";
message3 = ", and \"yahoo\"";
var reference = document.querySelector('.ref');
var el;
createOrUpdateCompositeLink(message, reference);
createOrUpdateCompositeLink(message1, reference);
createOrUpdateCompositeLink(message2, reference);
createOrUpdateCompositeLink(message3, reference);
<div class="ref"></div>
I would suggest you consider using jQuery and what you are trying to do becomes:
jQuery(".response").append(message);
I assume that your responsePara variable is defined from an existing <div> somewhere. In my example, that <div> would have a class named response.
<div class="response"></div>
Once you get a message, it gets added to the response div but that one line jQuery() command.
I am learning how to write object oriented javascript. I have a simple class to create div elements, but when I test the code no new elements are created. Am I doing this correctly? I am using the following code:
function elementCreation(elementParent, elementId, elementText) {
this.elementParent = document.getElementsByTagName(elementParent)[0];
this.elementId = elementId;
this.elementHtml = elementText;
this.elementMake = function (type) {
newElement = document.createElement(type);
// add new element to the dom
this.elementParent.appendChild(newElement);
};
}
var newObject = new elementCreation('body', 'testdiv', 'some text here!!!');
newObject.elementMake('div');
Your code works perfectly, congratulations.
You simply can't see an empty div without styling.
See here a demonstration with styling :
div {
width:100px;
height:100px;
background-color:red;
}
Note that if your construction parameters were intended for the construction of the child element, you have to put them to some use. For example :
function elementCreation(elementParent, elementId, elementText) {
this.elementParent = document.getElementsByTagName(elementParent)[0];
this.elementId = elementId;
this.elementHtml = elementText;
this.elementMake = function (type) {
newElement = document.createElement(type);
// add new element to the dom
this.elementParent.appendChild(newElement);
newElement.innerHTML = elementText;
};
}
Demonstration
I won't try to use the elementId parameter : if you define a function, it's probably to call it more than once and an id can't be used more than once in HTML.
The div is being created but you aren't setting it's content as your third argument elementText.
newElement = document.createElement(type);
newElement.innerHTML = this.elementHtml; // <-- set its content
newElement.id = this.elementId; // <-- set the ID
// add new element to the dom
this.elementParent.appendChild(newElement);
Added compatibility with firefox when setting text content, then associated the id attribute to the new element. I also tried another approach that could be easier to complexify.
What about:
function elementCreation(args) {
this.parent = args.parent;
this.id = args.id;
this.text = args.text;
this.make = function(type) {
var el = document.createElement(type);
el.id = this.id;
// firefox do not support innerText, some others do not support textContent
if (typeof el.innerText != "undefined") {
el.innerText = this.text;
} else {
el.textContent = this.text;
}
this.parent.appendChild(el);
}
}
new elementCreation({
parent: document.body,
id: 'div1',
text: 'some text here!!!'
}).make('div');
You can try it with this jsfiddle.