I have this img element in my HTML project:
<img id="themeToggle" src="./images/moon.svg">
and i want to change the source of this element to be "./images/sun.svg".
I tried with:
void main() {
var themeToggleButton = querySelector('#themeToggle');
themeToggleButton?.onClick.listen((event) {
themeToggleButton.dataset['src'] = './images/sun.svg';
});
}
since the .dataset attribute is the only one that lets you to access the selected element's attributes, but it does not work. Any suggestion, please?
You should be able to use the .attributes getter to get the attributes Map and set there the value:
themeToggleButton?.attributes['src'] = './images/sun.svg'
Note: .dataset (as specified in the docs) is used only for the element properties that start with data-
Related
I have created a custom element and placed on a page like this:
<my-custom-element [value]="100"></my-custom-element>
In the component definition, I have this:
#Input() value: number = 50;
At run-time, the value is always 50. I expect it to be 100. If I remove the default, value is undefined. What am I missing?
Thanks!!
In NG Elements you may not find in your OnIt but in OnChanges.
Please add below line and check it is defined.
public ngOnChanges(): void {
console.log('on changes value: ', this.value);
}
You can set data using HTML attributes and to change/update data in Angular Elements you have to use vanilla js, query selector and assign data like below
custom element tag with initial value = 0
<my-custom-element value="0" ></my-custom-element>
select custom element through the query selector and assign value.
var customElement = document.querySelector('my-custom-element');
customElement.value = 100;
This is the code snippet but I'm not able to understand how the observer method is working
static get properties() {
return {
selected: {
type: Object,
observer: '_selectedChanged'
}
};
}
_selectedChanged(selected, oldSelected) {
if (oldSelected) oldSelected.removeAttribute('selected');
if (selected) selected.setAttribute('selected', '');
}
connectedCallback() {
super.connectedCallback();
this.selected = this.firstElementChild;
}
full code: https://codelabs.developers.google.com/codelabs/polymer-2-carousel/index.html?index=..%2F..%2Findex#3
What is selected and oldselected and how can we do oldSelected.removerAttribute?
Are these objects of elements?
Please elaborate!
selected is property of element. It's value is some HTML element (in this case it's always img i think) so, in selected property there is always saved reference to img somewhere in html. When this property change, function _selectedChanged is called with 2 arguments. first argument is new image that is currently saved in selected and second argument is old image(previous value of selected).
further in tutorial you can see code
const elem = this.selected.nextElementSibling;
if (elem) {
this.selected = elem;
}
where is shown that const elem takes some html element and put it into this.selected.
So inside function _selectedChanged they removed html attribute from old image that was previously selected (so it was visible on screen) and added new html attribute to new image that should be visible on screen for now.
You can imagine that img with attribute selected is the only one that is shown on the screen at the time
I hope you understand my explanation. My english isn't 100% so if you have question, ask me and i can try to explain it more.
EDIT
Some example with binding and observer:
Let's say we have some paper-input which should show some results (articles for example) based on value of this input. So we have some HTML:
<paper-input value="{{search}}" label="Find articles"></paper-input>
this is primitive. Just some paper-input with value stored in search property. inside script tag:
Polymer({
is: 'test-el',
properties: {
search: {
type: String,
observer: "_findResults"
},
articles: {
type: Array
}
},
_findResults() {
this.set("articles", ['firstArticle', 'secondArticle', Math.random()]);
},
});
Explain: we defined property search and articles. Whenever property search changes, it calls function _findResults (because of observer). Function _findResults do only one thing. this.set("articles") is almost same as this.articles =. More about this can be found in documentation. So this.set("articles", ['firstArticle', 'secondArticle', Math.random()]); means it creates array and set it to articles property. and now, when we have some array that is changing everytime user enter some value in paper-input, we can add some HTML to show these articles:
<template is="dom-repeat" items="{{articles}}" as="item">
[[item]] <br>
</template>
I made also fiddle, so you can play with it and understand it a little bit more.
https://jsfiddle.net/2va41sy0/1/
Your question at the beginning was almost same in difference that they stored in some property reference to HTML object and not only just string. This is also about understand some basics of javascript and not polymer
This code from Dart worries me:
bool get isTemplate => tagName == 'TEMPLATE' || _isAttributeTemplate;
void _ensureTemplate() {
if (!isTemplate) {
throw new UnsupportedError('$this is not a template.');
}
...
Does this mean that the only way I can modify my document is to make it html5?
What if I want to modify an html4 document and set innerHtml in a div, how do I achieve this?
I am assuming you are asking about the code in dart:html Element?
The method you are referring to is only called by the library itself, and only in methods where isTemplate has to be true, for example this one. If you follow this link, you can also read what other fields/methods work like this.
innerHtml is a field in every subclass of Element which supports it, for example DivElement
Example:
DivElement myDiv1 = new DivElement();
myDiv1.innerHtml = "<p>I am a DIV!</p>";
query("#some_div_id").innerHtml = "<p>Hey, me too!</p>";
I'm trying to create a code snippet to remove all style attributes regardless of tag using HtmlAgilityPack.
Here's my code:
var elements = htmlDoc.DocumentNode.SelectNodes("//*");
if (elements!=null)
{
foreach (var element in elements)
{
element.Attributes.Remove("style");
}
}
However, I'm not getting it to stick? If I look at the element object immediately after Remove("style"). I can see that the style attribute has been removed, but it still appears in the DocumentNode object. :/
I'm feeling a bit stupid, but it seems off to me? Anyone done this using HtmlAgilityPack? Thanks!
Update
I changed my code to the following, and it works properly:
public static void RemoveStyleAttributes(this HtmlDocument html)
{
var elementsWithStyleAttribute = html.DocumentNode.SelectNodes("//#style");
if (elementsWithStyleAttribute!=null)
{
foreach (var element in elementsWithStyleAttribute)
{
element.Attributes["style"].Remove();
}
}
}
Your code snippet seems to be correct - it removes the attributes. The thing is, DocumentNode .InnerHtml(I assume you monitored this property) is a complex property, maybe it get updated after some unknown circumstances and you actually shouldn't use this property to get the document as a string. Instead of it HtmlDocument.Save method for this:
string result = null;
using (StringWriter writer = new StringWriter())
{
htmlDoc.Save(writer);
result = writer.ToString();
}
now result variable holds the string representation of your document.
One more thing: your code may be improved by changing your expression to "//*[#style]" which gets you only elements with style attribute.
Here is a very simple solution
VB.net
element.Attributes.Remove(element.Attributes("style"))
c#
element.Attributes.Remove(element.Attributes["style"])
Say I have a DOM that looks like this in my Document:
<body>
<div id="outer">
<custom-web-component>
#shadow-root (open)
<div id="inner">Select Me</div>
</custom-web-component>
</div>
</body>
Is it possible to select the inner div inside the shadow root using a single querySelector argument on document? If so, how is it constructed?
For example, something like document.querySelector('custom-web-component > #inner')
You can do it like this:
document.querySelector("custom-web-component").shadowRoot.querySelector("#inner")
In short, not quite. The TL:DR is that, depending on how the component is set up, you might be able to do something like this:
document.querySelector('custom-web-component').div.innerHTML = 'Hello world!';
Do do this - if you have access to where the web component is created, you can add an interface there to access inner content. You can do this the same way you would make any JavaScript class variable/method public. Something like:
/**
* Example web component
*/
class MyComponent extends HTMLElement {
constructor() {
super();
// Create shadow DOM
this._shadowRoot = this.attachShadow({mode: 'open'});
// Create mock div - this will be directly accessible from outside the component
this.div = document.createElement('div');
// And this span will not
let span = document.createElement('span');
// Append div and span to shadowRoot
this._shadowRoot.appendChild(span);
this._shadowRoot.appendChild(this.div);
}
}
// Register component
window.customElements.define('custom-web-component', MyComponent);
// You can now access the component 'div' from outside of a web component, like so:
(function() {
let component = document.querySelector('custom-web-component');
// Edit div
component.div.innerHTML = 'EDITED';
// Edit span
component._shadowRoot.querySelector('span').innerHTML = 'EDITED 2';
})();
<custom-web-component></custom-web-component>
In this instance, you can access the div from outside of the component, but the span is not accessible.
To add: As web components are encapsulated, I don't think you can otherwise select internal parts of the component - you have to explicitly set a way of selecting them using this, as above.
EDIT:
Saying that, if you know what the shadow root key is, you can do this: component._shadowRoot.querySelector() (added to demo above). But then that is quite a weird thing to do, as it sorta goes against the idea of encapsulation.
EDIT 2
The above method will only work is the shadow root is set using the this keyword. If the shadow root is set as let shadowRoot = this.attachShadow({mode: 'open'}) then I don't think you will be able to search for the span - may be wrong there though.
This code will behave like query selector and work on nested shadowDoms:
const querySelectorAll = (node,selector) => {
const nodes = [...node.querySelectorAll(selector)],
nodeIterator = document.createNodeIterator(node, Node.ELEMENT_NODE);
let currentNode;
while (currentNode = nodeIterator.nextNode()) {
if(currentNode.shadowRoot) {
nodes.push(...querySelectorAll(currentNode.shadowRoot,selector));
}
}
return nodes;
}