How to access root element's text in Polymer? - javascript

I'm writing an Polymer element that's supposed to be used like this:
<x-elem>Some text</x-elem>
The element would transform the text content. But when I try to access it in attached callback, it's empty:
attached: function() {
var text = this.root.textContent;
console.log(text); // Outputs ''
}
Frankly, the number of all child nodes is 0:
attached: function() {
console.log(this.root.childNodes.length); // Outputs 0
}
According to these docs I would think that at least my attempt at getting child nodes is correct, but apparently I do something wrong here. Perhaps I need to put something in my template (right now it's simple <template></template>, but it is not clear what.

this.root provides access to the element's local DOM (i.e., the DOM locally declared in the <dom-module>'s template), but you're trying to access light DOM (i.e., the DOM passed in). Use Polymer.dom(this).textContent for that:
HTMLImports.whenReady(() => {
Polymer({
is: 'x-foo',
attached: function() {
console.log('textContent:', Polymer.dom(this).textContent);
}
});
});
<head>
<base href="https://polygit.org/polymer+1.7.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo>hello world</x-foo>
<dom-module id="x-foo">
<template>
</template>
</dom-module>
</body>

Related

How do I call the JavaScript function properly?

<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript Example</title>
<script>
function displayString() {
return "<h1>Main Heading</h1>"
}
displayString();
document.write("Execute during page load from the head<br>");
</script>
</head>
<body>
<script>
document.write("Execute during page load from the body<br>");
</script>
</body>
</html>
So this is my problem. No matter where I put the displayString(), the h1 just never seems to show up on the browser. Can anybody please help me see where I am wrong? I am new to JavaScript. Oh, and what I am trying to do is to call the function.
You need to write the returned String to the document:
<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript Example</title>
<script>
function displayString() {
return "<h1>Main Heading</h1>"
}
document.write(displayString());
document.write("Execute during page load from the head<br>");
</script>
</head>
<body>
<script>
document.write("Execute during page load from the body<br>");
</script>
</body>
</html>
No matter where I put the displayString(), the h1 just never seems to
show up on the browser.
If you wish to add a new element to a document, several approaches are available:
document.write (effectively deprecated)
.innerHTML (sometimes useful, but can be slow)
DOM API - recommended approach
The recommended approach is to use the DOM API.
DOM stands for Document Object Model. Essentially it's the markup of your document represented as a tree-like structure of nodes. There are many DOM API functions which allow you to:
add
remove
append
prepend
insert
update
new DOM nodes.
Any DOM node may be added, removed or updated, including:
parent elements
child elements
sibling elements
element attributes
ids, classNames, classLists
custom data-* attributes
text nodes
Here is an example:
function displayMainHeading () {
let mainHeading = document.createElement('h1');
mainHeading.textContent = 'Main Heading';
document.body.prepend(mainHeading);
}
displayMainHeading();
<p>Paragraph 1</p>
<p>Paragraph 2</p>
Further Reading
This is a good primer to get you started:
A Beginners Guide To DOM Manipulation by Iqra Masroor

Object.defineProperty not changing property of element

I am trying to override the src property of all iframes in my application so their src property always gets set to "redirect.html" regardless of what value the HTML tag defines for it.
So far, I have come up with the following, but it doesn't seem to be applying to the DOM element:
<!doctype html>
<html>
<head>
<script>
var propertyDescriptorSrc = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "src");
Object.defineProperty(HTMLIFrameElement.prototype, "src", {
get: function get_src() {
var val = propertyDescriptorSrc.get.call(this);
return "redirect.html";
},
set: function (val) {
alert('setting: ' + val);
propertyDescriptorSrc.set.call(this, val);
}
});
</script>
</head>
<body>
<iframe src="page.html"></iframe>
</body>
</html>
I expected the iframe element in the body to load redirect.html instead of page.html, since I overrided its "getter", but it still loaded page.html.
Is there a way to force this behavior where all iframes by default go to redirect.html instead of whatever is defined in their src attribute?
(This is just an experimental project)
Before it starts javascript, the DOM tree is already parsed and contains all iframes together with its src, according to the Critical Rendering Path.
The only way to do this is by using javascript to redefine the src attributes of the individual iframe node. For example, as below.
all iframes are set to redirect.html:
<!doctype html>
<html>
<head>
</head>
<body>
<iframe src="page.html"></iframe>
<iframe src="page2.html"></iframe>
<script>
( function(){
var lng = document.getElementsByTagName('iframe').length;
for (var i=0; i<lng;i++){
document.getElementsByTagName('iframe')[i].src="redirect.html";
}
})();
</script>
</body>
</html>
According to the suggestion, #Aaron Digulla gives a more readable form of function.
It seems that the search algorithms of the DOM tree are so efficient today that the argument is the readability of the record, not the efficiency.
(function(){
var frames = document.getElementsByTagName('iframe');
for (var i=0; i<frames.length;i++){
frames[i].src="redirect.html";
}
})();

Pass DOM nodes to Polymer as attributes

Ok, so I'm defining a polymer object like this:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="my-element" attributes="content">
<template>
<div class="someclass">
{{content}}
</div>
</template>
<script>
Polymer({});
</script>
</polymer-element>
Which works fine if I instantiate it as:
<my-element content="test"></my-element>
However, I'd like to be able to pass HTML inside the element. If I do this:
<my-element content="<div>test</div>"></my-element>
The HTML is not added to the DOM, but displayed as text. Is it possible to pass HTML inside a polymer element? Or am I doing something completely wrong here?
Thanks for any help!
Here's some hackish code I made that may answer your question.
http://jsbin.com/hedutu/edit?html,output
Basically, I created an observer for an attribute that accepts DOMs in string format and then inserted that dom into a local dom node.

JQuery $('#id") does not work

I'm a noob in JQuery, trying my hands on the basic functionality of it
I have a html, like below.
<html>
<head>
<script type="text/javascript" charset="utf-8" src="js/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="js/start.js"></script>
<script>
$(mainFunction());
$('#label1').prop('innerHTML', "test");
</script>
<title></title>
</head>
<body>
<label id="label1"></label>
</body>
</html>
From start.js, i'm trying to manipulate the elements in this html file like below.
function start(name){
this.iam = name;
this.getName = function(user){
return this.iam;
}
}
function mainFunction(){
var label = $('#label1');
var oStart = new start("test");
label.prop("innerHTML" ,oStart.getName("test"));
}
When I try to lookup whats in the 'label' in the above code, i get [] printed on the console. What am I doing wrong here?
$(mainFunction()); is your issue. Instead provide function reference to document.ready.
Like this:
$(mainFunction);
While doing $(mainFunction()); you are invoking the function mainFunction while setting up the handler, which means it gets executed too early before the DOM tree has been constructed.
Or in order to avoid confusion you could do:
$(function(){
mainFunction();
});
Also remember that this issue will not happen if you move your script just before the end of the body tag. You do not have to listen to document ready handler. Plus as a shorthand you could just do label.html(oStart.getName("test"));
You need to wait for the DOM to be ready before using jQuery.
This is done this way:
$(document).ready(function() {
// All your code touching the DOM in here
});
Also note that this line: $(mainFunction()); uses the return value of mainFunction, it does not trigger it when DOM is ready.

Get the content of another page's div with jQuery Ajax

I would like page.html to ajax-request the content of side.html and extract the content of two of its divs. But I cannot find the correct way to parse the response, despite everything I tried.
Here is side.html:
<!DOCTYPE html>
<html>
<head>
<title>Useless</title>
</head>
<body>
<div id="a">ContentA</div>
<div id="b">ContentB</div>
</body>
</html>
and here is page.html
<!DOCTYPE html>
<html>
<head>
<title>Useless</title>
<script type='text/javascript' src='jquery-1.9.0.min.js'></script>
</head>
<body>
Hello
<script type="text/javascript">
jQuery.ajax({
url: "side.html",
success: function(result) {
html = jQuery(result);
alert(html.find("div#a").attr("id"));
alert(html.find("div#a").html());
alert(html.find("div#a"));
},
});
</script>
</body>
</html>
When I access this page, I get no error, and the three alert()s yield undefined, undefined and [object Object]. What am I doing wrong? Example is live here.
You need to change this line:
html = jQuery(result);
To this:
html = jQuery('<div>').html(result);
And actually, even better you should declare this as a local variable:
var html = jQuery('<div>').html(result);
Explanation
When you do jQuery(result), jQuery pulls the children of the <body> element and returns a wrapper around those elements, as opposed to returning a jQuery wrapper for the <html> element, which I tend to agree would be pretty dumb.
In your case, the <body> of sidebar.html contains several elements and some text nodes. Therefore the jQuery object that is returned is a wrapper for those several elements and text nodes.
When you use .find(), it searches the descendants of the elements wrapped by the jQuery object that you call it on. In your case, the <div id="a"> is not one of these because it is actually one of the selected elements of the wrapper, and cannot be a descendant of itself.
By wrapping it in a <div> of your own, then you push those elements "down" a level. When you call .find() in my fixed code above, it looks for descendants of that <div> and therefore finds your <div id="a">.
Comment
If your <div id="a"> was not at the top level, i.e. an immediate child of the <body>, then your code would have worked. To me this is inconsistent and therefore incorrect behaviour. To solve this, jQuery should generate the container <div> for you, when it is working its <body> content extraction magic.
Try this :
$.get(url,function(content) {
var content = $(content).find('div.contentWrapper').html();
...
}

Categories

Resources