Within my Polymer (v1.2.3) element, I need to dynamically append newly created DOM elements to certain local DOM nodes. The elements I am appending contain a class="foo", where class foo has styles scoped within my polymer element.
The problem I am facing is that these styles are not applied to the elements.
The following code will exemplify the issue:
attached: function () {
var el = document.createElement("span");
el.textContent = "Woof. Woof. Meow!";
el.classList.add("foo");
Polymer.dom(this.root).querySelector(".bar").appendChild(el);
}
Here is my template:
<dom-module id="my-element">
<template>
<style>
.foo {
color: red;
}
</style>
<div class="bar"></div>
<div class="baz"><span class="foo">I am not added dynamically!</span></div>
</template>
...
</dom-module>
In the above template, the element .foo within .baz will have styles applied to it but, element .foo within .bar would not (polymer's class style-scope is no applied to it).
Some additional info:
style-scope not added to dynamically created elements.
Polymer.dom(this.root).appendChild(el) applies styling but, does not add it at desired location.
Calling updateStyles() or Polymer.dom.flush() explicitly after the element is added, does not resolve the issue.
Polymer version 1.2.2 also contains this issue
There is an open bug that requires to append :host:: content as a prefix to each style.
Related
In my header.php template, I have a button that looks like this, in my stylesheet, I have the following CSS code and In an already enqueued JS file, I have this:
function NightModeToggle(){
var element = document.body;
element.classList.toggle("NightModeToggle");
}
.NightModeToggle{
background-color: black;
color: white;
}
<button onclick="NightModeToggle()">Dark</button>
I understand that it targets the body by using this line: var element = document.body;
My question is, how do I add additional targets so that I can change the background color and text color of the header and footer as well?
I tried modifying the code into this (without result):
var element = document.body;
var element = document.header;
var element = document.footer;
Any ideas?
Depending on the structure of your HTML, you will need to target your other elements by using document.querySelector() and passing in the selector of the element you want to target, e.g.:
document.querySelector('footer') // If you use a <footer> tag
document.querySelector('#footer') // If you use e.g. <div id="footer">
document.querySelector('.footer') // If you use e.g. <div class="footer">
You can also use document.querySelector('body') instead of document.body to keep this approach consistent.
The reason document.body works is that body is a property of the document object that contains the contents of the document (the <body> tag). Similarly, document.head will return the content of the <head> tag in your HTML.
I am attempting to query the children of a custom element which uses a content tag as an injection point for its children.
<dom-module id="content-element">
<template>
<content id="content"></content>
</template>
<script>
Polymer({
[...],
attached: function() {
console.log(this.queryAllEffectiveChildren('div'));
// console.log(this.children);
}
});
</script>
</dom-module>
Its parent generates an appropriate element and then appends it into the content-element.
<dom-module id="parent-element">
<template>
<content-element></content-element>
</template>
<script>
Polymer({
[...],
ready: function() {
var newEl = document.createElement('div');
Polymer.dom(this.root).querySelector('content-element').appendChild(newEl);
}
});
</script>
</dom-module>
When I inspect the DOM, the div will appear inside of the content-element as expected. The problem is that when the attached method is executed, it returns an empty HTML collection.
I know that the content-element has children though. If I console.log(this.children) in the same attached method, I will get an HTML collection with the div in it. I have also noticed that if I 'hard code' the div, querying the effective children will yield an HTML collection containing the div.
<content-element>
<div></div>
</content-element>
The ability to query the effective children is important as the number of divs being appended will grow and I will need to be able to filter them by class.
this.queryAllEffectiveChildren('.red-divs-only');
This will not be possible using this.children as an HTML collection is not editable like an array.
Update
If I add a public method called addElement to the content-element, which appends an element passed to it by the parent, I am able to get results with queryAllEffectiveChildren(). However, I do not understand why this works and the other way does not.
<dom-module id="content-element">
<template>
<content id="content"></content>
</template>
<script>
Polymer({
[...],
addElement: function(el) {
Polymer.dom(this).appendChild(el);
},
attached: function() {
console.log(this.queryAllEffectiveChildren('div'));
}
});
</script>
</dom-module>
<dom-module id="parent-element">
<template>
<content-element></content-element>
</template>
<script>
Polymer({
[...],
ready: function() {
var newEl = document.createElement('div');
var conEl = Polymer.dom(this.root).querySelector('content-element');
conEl.addElement(newEl);
}
});
</script>
</dom-module>
The answer to this problem lies in where the children are being appended.
Polymer.dom(this.root).querySelector('content-element') is targeting the local root, which is not where the children should be appended for use with a content tag.
Instead one should follow the instructions laid out in the Polymer documentation for appending children to the light dom. This can be done by passing a node to a public method where the element can append the node to itself:
addElement: function(el) {
Polymer.dom(this).appendChild(el);
}
Also, the light DOM can be targeted directly:
var newEl = document.createElement('div');
var conEl = Polymer.dom(this.querySelector('content-element')).appendChild(newEl);
Following one of these methods will allow light DOM Polymer methods to interact properly with children of an element using a content tag.
I am trying to obtain the font-size currently applied to a cloned element, but when I use the jQuery .css function, it doesn't retrieve anything.
Is it not possible to use the ".css" function in jQuery to retrieve a specific css property from a cloned element?
The following does not work:
var clonedElement = jQuery('.element').clone();
clonedElement.attr("style", "");
var defaultFontSizeValue = clonedElement.css('font-size');
console.log(defaultFontSizeValue);
Edit 1
The original unfortunately has inline styles that don't allow me to get the overridden font-size property for that element that is applied via a class. This is why I am trying to retrieve that original value by removing the inline styles in the clone.
Your problem is that the cloned element is not "attached" to your dom, and therefore there is no style definition to this element (based on css that are not inline).
What you can do is append the cloned element to the body (after setting display: hidden, if you want), and then check the font-size:
$(function() {
console.log($('.c1').css('fontSize'));
c1 = $('.c1').clone();
console.log(c1.css('fontSize'));
c1.css('display', 'none');
$('body').append(c1)
console.log(c1.css('fontSize'));
});
.c1 {
font-size: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="c1">asd</div>
I am using javascript to inject a few DOM elements into the page. I am able to inject a single DOM element and apply CSS style to it:
var $e = $('<div id="header"></div>');
$('body').append($e);
$e.css({
background: '#fbf7f7',
});
Problem: If I have nested elements within $e, how can I apply CSS styles to the parents and its children seperately?
var $e = $('<div id="header"><div class="header-content"><span class="title"></span></div></div>');
As you have applied class to div inside parent element you can simply create a style to that class header-content and apply it.
In order to apply styles dynamically you can simply add class for individual elements like this
$('#id-of-element').addClass("header-content");
you can also find elements inside parent element like the one below
$e.find('.header-content').css('background-color', '#ccc');
Hi you can add css to any element using .css() method... Try the following example. I have added a div inside $e and applied different style... the thing is to use the id or class of the child inside parent div...
var $e = $('<div id="header"><div id="child"></div></div>');
$('body').append($e);
$e.css({
background: '#fbf7f7',
});
$('#child').css("background", "red");
To expand on my comments: if you need to access children regardless of any id or class, then just use $e.children().
is it possible to disable css styles for specific group of html elements?
To be more specific, I have html document and many css styles and I want to set default css for some elements (or remove/disable all styles for those elements).
Is there any way to do this using html/css/javascript? Setting all styles to default one by one takes time.
In addition I can say that it can be done by nesting part of code to iframe (because it doesn't inherit styles) but it is not much pretty way at all.
Thanks for help.
Add a class to the <body> tag?
HTML
<body class="default-theme">
<p> ... </p>
<ul>
<li> .. </li>
<ul>
</body>
CSS
body.default-theme p {
... default settings ...
}
body.default-theme li {
.. more css ...
}
How are the elements grouped? Is it by a particular class name? If so you could do the following to clear out the style's or set them to a particular value
var all = document.getElementsByTagName('theClass');
for (var index in all) {
var element = all[index];
element.style = {};
}
If you control the stylesheet, then you can just make all the styles depend upon a master class in the body element. Then, you can turn all those rules on/off by simply adding or removing that class from the body element.
Suppose the class name is "master". When the "master" class name is on the body element like this:
<body class="master">
then all these rules will be in force:
.master .selected {color: blue;}
.master #breadcrumb {color: red;}
If you then remove the "master" class from the body tag with script, all those rules will stop being applied instantly.
Obviously, you don't have to use the body tag. You can use any common parent object of all the effected elements.