Selecting element (Polymer 1.0) - polymer

I am working on migrating to Polymer 1.0
Here is my template:
<template>
<div class="scroll">
<div class="content">
<content></content>
</div>
<div class="bar barY"></div>
</div>
</template>
The content gets filled with text in the main html file.
I need to get the scroll height of this div. I used to do:
height = $(this.shadowRoot).find('.content')[0].scrollHeight;
But this isn't working anymore:
Uncaught TypeError: Cannot read property 'scrollHeight' of undefined
I tried adding an id to the div, and selecting it like so:
height = this.$.content.scrollHeight;
But this is giving me a value of 0, even though there is lots of text in the content.
I am calling this code from the ready function.
Am I selecting the element correctly?

<content> does not actually contain the component's contents, rather it provides an insertion point for those contents, which will be siblings to the <content> element. To get the elements which are inserted for a given <content> node, you can use the following:
var content = Polymer.dom(this.root).querySelector('content');
var distributed = Polymer.dom(content).getDistributedNodes()
Documentation for the above can be found at https://www.polymer-project.org/1.0/docs/devguide/local-dom.html#dom-api-examples along with a more complete example.

Related

Dialog element from file

I've been reading with interest about the dialog element in HTML:
<dialog id="helpOnName">
<p>
The name is arbitrary. There is no validation, whatsoever.
</p>
</dialog>
So, that's well for this simple text. However, with growing complexity, I'd rather have something like
<dialog url="helpOnName.html"></dialog>
In other words: Rather than embedding the dialog contents into the opening page, I'd like it to be read from another file.
Is that possible? How? (Using JQuery would be fine.)
You may have different options to achieve the goal to have content loaded from an external resource.
Doing an ajax request that will return a response to embed
dynamically in the dialog
Embedding the content inside an <iframe> tag
Referencing the content with an <object> tag
This is the demo for the third and most original option of those.
The content for the <dialog> is specified by an <object> element fed by an url having its content. As a fallback, I added the option that will override its content with a default template defined in the page itself.
<object>: The External Object element
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object
:scope (worth of mention)
*for selecting only starting from the direct children
https://developer.mozilla.org/en-US/docs/Web/CSS/:scope
This is an answer better covering <iframe> <embed> <object>
Difference between iframe, embed and object elements
And I would add I forgot to mention <link>
document.addEventListener('DOMContentLoaded', ()=>{
const dialog = document.getElementById('primaryDialog');
fillDialogContent(dialog);
})
function fillDialogContent(dialog){
const template = dialog.querySelector(':scope > .fallback');
const content = template.content.cloneNode(true);
const objectEl = dialog.querySelector('object');
objectEl.append(content);
}
<dialog id="primaryDialog" open>
<object data="your-custom-dialog-content.html" type="text/html"></object>
<template class="fallback">
<div class="container">
<p>This is the default dialog content</p>
<p>An error occurred in the attempt to load the custom template</p>
</div>
</template>
</dialog>
Here is another way of doing it with fetch():
document.addEventListener('DOMContentLoaded', function(ev) {
document.querySelectorAll("[data-url]").forEach(el=>
fetch(el.dataset.url).then(r=>r.text()).then(html=>el.innerHTML=html)
)
});
<h3>First dialogue</h3>
<div data-url="https://baconipsum.com/api/?type=all-meat&paras=3&format=html">hello</div>
<h3>Second dialogue</h3>
<div data-url="https://baconipsum.com/api/?type=all-meat&paras=5&make-it-spicy=1&format=html">hello again</div>

Angular - Scroll to the bottom of an element

So I have this 'output' element which fills up with messages, the overflow is set on scroll so after a certain amount of messages this element becomes scrollable. It doesn't auto scroll to the bottom though, so I tried doing this using the DOM, document.getElementById('output'), this didn't work and after some reading I learned this should be avoided in angular.
So I want to target this #output element in my output-window component with my typescript and access some scrollTo() method to scroll it to the bottom, how should I do this?
output-window.component.html:
<div id="output">
<p *ngFor="let message of messages">
{{ message }}
</p>
</div>
Project structure
home.component
+-->output-window.component
+-->div#output
Targeting this div#output is what's giving me trouble.
retrieve p tags with view children
#ViewChildren("p") ps: QueryList<any>
ngAfterViewInit() {
this.ps.last.nativeElement.scrollIntoView();
}
then access to native element and then scroll to it.
or better approach is write a directive for p element and set it for last element
Edit : It seems you need to name your p element like below
<div id="output">
<p *ngFor="let message of messages" #p>
{{ message }}
</p>
</div>
in order to make ViewChildren work properly.
I have created a stack blitz for you. Please check here

Replace text in a span that also contains other DOM elements

I have a code like this and I need to remove the ​ characters that are inserted automatically by the code that I have no control over (generated by SharePoint). They ruin the layout by inserting extra empty lines:
<div id="ctl00_PlaceHolderMain_ctl01__ControlWrapper_RichHtmlField" class="ms-rtestate-field" style="display:inline" aria-labelledby="ctl00_PlaceHolderMain_ctl01_label">
​​​
<span> ​
<div class="cg-division-intro-outer">
<div class="cg-division-intro-inner">
<div class="cg-division-intro-header">
<h1>Division Intro</h1>
</div>
... etc
Notice that the ​ entities are inserted as bare text, not wrapped into any element, so I cannot target them directly.
Here is what I tried:
Using visibility: hidden on the element containing the garbage and visibility: visible on my code. Has no effect.
Reducing font-size on the parent element containing the garbage to 0px and restoring the font-size on other elements. Has no effect.
Obtaining the innerHTML of the parent element, doing the .replace() and reinserting HTML back into the page - but then all the nodes will be lost/recreated, which means any attached listeners may be lost.
Tried using :not but didn't come up with a solution that works.
Here is the white bar created by those ​s:
DEMO
JS
use childNodes and change its value by nodeValue
var d = document.getElementById('div1').childNodes[0];
d.nodeValue = "new text"; // change value
// if you want to remove the element
d.parentElement.removeChild(d)
HTML
<div id="div1">
some texts
<div id="div2">
other elements
<div>hkeqvdkqbdklq</div>
</div>
</div>

XPath for getting nodes from HTML fragment based on element text content

I need an XPath expressions for the following HTML fragment (DOM structure)
<div class="content">
<div class="product-compare-row">
<div class="spec-title half-size">Model</div>
<div class="spec-values half-size">
<span class="spec-value">kast</span>
</div>
</div>
So I need the kast value if the spec-title div contains Model.
I've tried //div[preceding-sibling::div[contains(.,"Model)")]] but that doesn't work.
The XPath you are looking for is:
//div[contains(#class, "spec-title") and contains(text(), "Model")]/following-sibling::div/span/text()
It is a little bit tricky to follow, but in plain English:
Select all div elements who have a class spec-title and who have text that contains 'Model'.
Find any of this div's following siblings if they are a div.
Traverse to any of their children which are a span and return their text.

Need to make a "bulletproof" div

How do i make a div that will not break even if the structure of the information inside it is improperly made.
ie:
<div id="bulletproof_div">
<div> </div>
<div> </div>
<div id="unclosed_div">
</div>
<div id="normally_this_one_would_break">
</div>
edit: the context is that it is a mailing system where i have no control over the information that is being sent to me, that is why i need to make it so that the website will not break.
i have tried successfully with iframe but i need to be able to modify the inner html of the div so iframe is not ideal.
Thank you for reading
Iframes are the only 100% bullet-proof containers to isolate contents from the surrounding page.
If you have access to the broken markup before it is appended to the 'bulletproof_div' you can use this function to 'fix' the markup before it is appended
function cleanMarkup(markupStr) {
// temp 'div' only used as a container, it is not returned with output
var temp = document.createElement("div");
temp.innerHTML = markupStr;
return temp.innerHTML;
}
Most browsers will attempt to fix broken markup, so when you retrieve the innerHTML property immediately after setting it, the value will be a 'fixed' markup string.
So given this input
cleanMarkup("<div></div> <div id='unclosed'>test!")
The function should return
<div></div> <div id="unclosed">test!</div>