I have an element in local storage with multiple elements, for simplicity, I will make the element:
<div id="outer">
<ul id="inner">
<li id="item">
</li>
</ul>
</div>
The element is saved as a string and I want to manipulate the contents.
Like such:
let local_storage_element = localStorage.getItem("val")
$(local_storage_element+':last-child').append("<p>something</p>")
No matter what selector I add after local_storage_element it will always append the value to the string not to the selected element(:last-child in this case)
does anyone know how to append to a specific element within the string??
Although you have written jquery in the title there is a javascript tag added also so I thought why not provide an answer that justifies your needs and helps you accomplish the task in the same way you want.
The
DocumentFragment interface represents a minimal document object that has no parent. It
is used as a lightweight version of Document that stores a segment of
a document structure comprised of nodes just like a standard document.
The key difference is that because the document fragment isn't part of
the active document tree structure, changes made to the fragment don't
affect the document, cause reflow, or incur any performance impact
that can occur when changes are made.
So how to do it as the DocumentFragment still appends node with it and not string, we will create a temp element and add the HTML from the localStorage using innerHtml and then append the firstChild of that temp node i.e our actual string which is now treated as a node, to the document fragment and then search and appends HTML to it, we will use our temp element to add HTML every time see below.
I will append a new child div to the element #outer in the string given above in the post here is the working FIDDLE as SO does not support localStorage you can see it working there open the console to view the resulting HTML with the new child added and below is the code
$(document).ready(function () {
if (localStorage.getItem('html') === null) {
localStorage.setItem('html', '<div id="outer"><ul id="inner"><li id="item"></i></ul></div>');
}
var frag = document.createDocumentFragment();
var temp = document.createElement('div');
temp.innerHTML = localStorage.getItem('html');
frag.appendChild(temp.firstChild);
temp.innerHTML = '<div class="new-child"></div>'
frag.querySelector("#outer").appendChild(temp.firstChild);
console.log(frag.querySelector("#outer"));
localStorage.removeItem('html');
});
You can't use string as selector. If you want transform string to html then you should put it in some element as innerHTML. So try create some hidden div and insert your string as HTML to it. Something like this
var your_string = '<ul><li>1</li><li>2</li><li>3</li><li>4</li></ul>';
document.querySelector('.hidden').innerHTML = your_string;
document.querySelector('ul li:last-child').innerHTML = 'your content';
document.querySelector('.result').appendChild(document.querySelector('ul'));
Example
The problem may arise when you get '<div id="outer">' from localStorage to use it as a selector since it only accepts "#outer" to be a selector. If you want to add an element to be the last child of parent's element, you could use after() instead of append().
$(document).ready(() => {
if ($("#charl").children().length === 0)
{
// if using after with no element inside ul then it will be inserted after il
$("#charl").html("<li>foo</li>")
}
else {
$("#charl li").after("<li>bar</li>")
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="charl">
<li>Foo</li>
</ul>
Related
Suppose the following example:
let html = `<Parent customAttr={ value }>
<Child className="container" />
</Parent>`;
let div = document.createElement('div');
div.innerHTML = html;
// or
div.insertAdjacentHTML('beforeend', html);
console.log(div);
When inserting the html variable as innerHTML of the div, first letters of <Parent> and <Child> elements become lowercased, camelCase of the attributes are lost and { value } becomes wrapped into double quotes.
Is it possible and how to keep everything without these changes when inserting as innerHTML?
from mdn web docs :
What exactly happens when you set value of innerHTML? Doing so causes
the user agent to follow these steps:
The specified value is parsed as HTML or XML (based on the document
type), resulting in a DocumentFragment object representing the new set
of DOM nodes for the new elements. If the element whose contents are
being replaced is a element, then the element's
content attribute is replaced with the new DocumentFragment created in
step 1. For all other elements, the element's contents are replaced
with the nodes in the new DocumentFragment.
so you can't do what you want with innerHtml
You can simply add content to the element.
div.innerHTML += html
I want to create several elements using JSON data with a template, by creating a clone of the template and appending them to the specific div.
However, when using the cloned template variable, the clone can't be used inside the function which handles the JSON data, even when this clone is above the function (which should make it global for everything the same level?).
HTML
<template class="content">
<h2>Hello World</h2>
<h3>Hello World</h3>
</template>
<div class="box">
</div>
JS
let content = document.querySelector(".content").content;
let box = document.querySelector(".box");
doStuff();
function doStuff() {
let content = document.querySelector(".content").content;
let box = document.querySelector(".box");
//make a clone of the template
let clone = content.cloneNode(true);
// change content of H2
clone.querySelector("h2").textContent = "First Box";
// change content of H3 with data fetched from API
fetch("http://kea-alt-del.dk/t5/api/product?id=21").then(e => e.json()).then(productJson => otherStuff(productJson));
function otherStuff(productJson) {
clone.querySelector("h3").textContent = productJson.name;
}
// add the clone to the box div
box.appendChild(clone);
}
Working fiddle as Example: https://jsfiddle.net/c1x98hmh/4/
We can see in the result that the h2 content has been changed, however, h3 remains unchanged. Console log tells me that clone is null.
How come this example works when we change the template element to a div?
(I need this for Json, that's why I have a template, function, clone and inside function)
clone is a DocumentFragment object. Here's what appendChild does with a DocumentFragment:
If the given child is a DocumentFragment, the entire contents of the DocumentFragment are moved into the child list of the specified parent node.
keyword being "moved" — that's why clone is empty when otherStuff is called.
My guess is that since the <template> element is not to be rendered by the browser, its content is not part of the DOM and thus it is not possible to query it with a DOM query such as document.querySelector().
EDIT: It is confirmed here: https://www.html5rocks.com/en/tutorials/webcomponents/template/
Content is considered not to be in the document. Using document.getElementById() or querySelector() in the main page won't return child nodes of a template.
How can I copy the whole <img /> using jquery.
At the moment I am trying: $('img').clone().html()
Usage:
'<div class="content-left">'+$(this).find(".bar .info").html()+$(this).find(".bar img").clone().html()+'</div>';
To create new copies of every image in the DOM you can select them and clone them, then append them to some container.
//store a clone of all the images in the DOM in a variable
var $clone = $('img').clone();
//now add the clones to the DOM
$('#newContainer').html($clone);
Here is a demo: http://jsfiddle.net/jasper/r3RDx/1/
Update
You can create your HTML like this:
//create a new element to add to the DOM
//start by creating a `<div>` element with the `.content-left` class
//then add a string of HTML to this element
//then append a set of DOM elements (clones) to the same parent element (the `<div>`)
var $newElement = $('<div />').addClass('content-left').html($(this).find('.bar .info').html()).append($(this).find('.bar img').clone());
//then you can add the new element(s) to the DOM
$newElement.appendTo('#newContainer');
Here is a demo: http://jsfiddle.net/jasper/r3RDx/2/
jQuery objects are simple arrays containing the html of the selected element. This means that I can simply do: $('img.someclass')[0] to access the html of the first (and probably only) matched element.
clone includes the event handlers of the object. If you want just the html whats below would be fine
$('#someid').html($('img'))
I have HTML in a JavaScript string (containing usual, nested HTML). Using jQuery, can I convert that into a valid HTML element in a single stroke using any of the document.create* functions? My requirement is to use document.getElementById on the created DOM object.
Take simple nested example.
var dom_string = '<div>xxx<div>yyy</div></div>';
create HTML DOM elements using $() function of jquery and append wherever you want.
i have taken 'body' but you can append anywhere.
$(dom_string).appendTo('body');
Alternatively you can implement this with pure javascript:
var dom_target = document.getElementById("target");
dom_target.innerHTML = dom_string;
Create a dummy element and set its innerHTML to your HTML string.
// Construct a container as a placeholder for your content
var container = document.createElement('div');
container.id = 'container';
// Inject the container into the DOM
document.body.appendChild(container);
// Populate the injected container with your content
container.innerHtml = '<p id="pTag">I am a <em>P</em> tag with some <strong>nested markup</strong>.</p>';
To convert Html text into a Jquery-Object use the $() function:
div = '<div>hello world</div>';
$div = $(div);
But as others have noted in most cases you don't need that because DOM manipulation functions like append() and prepend() will accept plain text, so
$('body').append('<div>hello world</div>');
is absolutely fine.
For example I have this HTML:
<body>
<div>Text</div>
</body>
And I would like to change the div to something else like p.
This is what I have tried but doesn't works:
var div = document.getElementsByTagName("div")[0]; // Get Element
div.nodeName = "p"; // Change It's Node Name to P
Please no libraries, and I don't really want to replace the actual div with a new p :)
You cannot just change an element. You have to create a new one. E.g.:
var div = document.getElementsByTagName("div")[0];
var p = document.createElement('p');
p.innerHTML = div.innerHTML;
div.parentNode.replaceChild(p, div);
But this could lead to invalid markup, if the original element contains nodes that cannot be descendants of the new node.
Reference: document.createElement, Node.replaceChild
Note: A better version (because it doesn't depend on serializing DOM to text and back and preserves attributes), can be found at https://stackoverflow.com/a/8584158/218196 .
The reason you can't just change the tagName property is because different HTML tags are actually different classes of objects. A div tag is an HTMLDivElement instance, a p tag is an HTMLParagraphElement instance, and so on. These classes can have vastly different properties and interfaces, so turning one into another is not as trivial as you'd think.
You can't.
As the MDC docs say:
nodeName is a read-only attribute.
You'll have to create a new element and give it the right content and attributes.
You cannot. The propery you're after is tagName, but it is read only. You would instead have to create a new node of the desired type, then transfer the innerHTML (and any other properties like className or style) to the new node. Then, insert the new node into the old node's parent, then remove the old node (or use replaceChild).
In other words, the long road is the only road.
I solved this in an XML scenario (eg. where there is no innerHTML) like so:
function renameNode (node, newNodeName) {
const newNode = node.ownerDocument.createElement(newNodeName);
Array.from(node.attributes).forEach(attr => newNode.setAttribute(attr.localName, attr.value));
Array.from(node.childNodes).forEach(childNode => newNode.appendChild(childNode));
node.parentElement.insertBefore(newNode, node);
node.parentElement.removeChild(node);
}
Does not return anything, but will update your DOM.