Accessing element attributes before Polymer element registration - javascript

I'd like to declare attributes directly on a Polymer element, which are then passed inside the element and are readable/accessible outside of the element script.
I'd like to use the values of such attributes for deciding how to register the element.
tl;dr
I'm having an issue where I need to register an element some time after the whole page has loaded - i.e I want to manually register the element.
A solution for registering elements on demand:
<dom-module id="foo-element">
<template>
<span> Foo element </span>
</template>
</dom-module>
<script>
window.addEventListener("app-ready", function() {
"use strict";
Polymer({
is: "foo-element",
properties: {
//..... rest of element properties, methods, etc
Explaining what I'm doing above:
Instead of using HTMLImports.whenReady(<element-registration-code>), I use addEventListener(event, <element-registration-code>
I broadcast app-ready when I want the registration to happen
This allows me to register the element, on-demand
The reusability problem of the above solution
This poses a severe reusability problem - while this element in one of context needs to be registered at some specific point in time, in other context it might not - it should register itself using the standard HTMLImports.whenReady(<elementCode>) method.
An ideal example:
<!-- Registers automatically when `HTMLImports` are ready, the "regular" way-->
<foo-element></foo-element>
<!-- Registers only when it picks up an `app-ready` event-->
<foo-element no-auto-register register-on-event="app-ready"></foo-element>
and the element could look something like this:
<dom-module id="foo-element">
<template>
<span> Foo element </span>
</template>
</dom-module>
<script>
// if `no-auto-register` is set on the element,
// do not use `HTMLImports.whenReady()` and use
// `addEventListener` to register when an event
// with the value of `register-on-event` property fires.
</script>
Long story, short
Is there any way to declare a flag/property/attribute directly on the element which would decide how the registration should happen?

Passing an attribute to element might not work as element needs to be in ready state for that. Below are three ways that might help you with what you are trying
One way to lazy register your elements in Polymer is to use Polymer.Class instead of Polymer constructor. This way until you register your element manually it will not get rendered. Below is an working example of same.
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="polymer/polymer.html">
<dom-module id="poly-form">
<template>
<style></style>
I am parent Element
<div>
<button onclick='register()'>Save</button>
</div>
<show-form></show-form>
</template>
</dom-module>
<script>
Polymer({
is: 'poly-form',
});
//element to lazy register
var showForm = Polymer.Class({
is: 'show-form',
ready: function() {
this.textContent = 'I am working...';
}
});
function register() {
var form = document.querySelector('poly-form');
//lazy register the element
document.registerElement('show-form', showForm);
}
</script>
<poly-form></poly-form>
In this example show-form element does not render until the button is clicked.
Note I've never really tried this with element containing dom.
Second way this should also be possible with importHref method.
Third way is global setting lazy-register where element gets register only when its first instance is called.
Sorry, the snippet is not as well constructed as it could have been. Hope it helps.

Class Style Constructor
If you want to set up your custom element's prototype chain but not register it immediately, you can use the Polymer.Class function. Polymer.Class takes the same prototype argument as the Polymer function, and sets up the prototype chain, but does not register the element. Instead it returns a constructor that can be passed to document.registerElement to register your element with the browser, and after which can be used to instantiate new instances of your element via code.
var MyElement = Polymer.Class({
is: 'my-element',
// See below for lifecycle callbacks
created: function() {
this.textContent = 'My element!';
}
});
document.registerElement('my-element', MyElement);
// Equivalent:
var el1 = new MyElement();
var el2 = document.createElement('my-element');

Related

Nested HTML element not assigning to slot

In the below code I am trying to assign <span slot='test-slot'>b</span> to <slot name='test-slot'>a</slot> but the assignment does not work. If I bring <span slot='test-slot'>b</span> outside of its parent <div> container the assignment does take place as expected.
Why is this? Is there anyway you can assign from nested elements with the slot element? If not, any alternatives? This is obviously a reduced test case but in my real web component, it is much more intuitive for a user to add an element with the slot tag within other containers.
<test-element>
<div>
<span slot='test-slot'>b</span>
</div>
</test-element>
<template id='template-test-element'>
<slot name='test-slot'>non slotted content</slot>
</template>
<script>
class TestElement extends HTMLElement {
constructor() {
let template = document.getElementById("template-test-element")
.content.cloneNode(true);
// Initialise shadow root and attach table template
super() // sets AND return 'this' scope
.attachShadow({mode:"open"}) // sets AND returns shadowRoot
.append(template);
}
}
customElements.define('test-element', TestElement);
</script>
Named slots only accept top-level children that have a matching slot-attribute.
See this (old) Polymer explainer or this more recent article.
Edit: Not sure where this is coming from though, the spec fails to mention this requirement: https://html.spec.whatwg.org/multipage/dom.html#attr-slot
It also is neither mentioned here nor here.

How to add custom attribute for element using vue directives?

I have custom attribute my-custom-attribute which contains the id for the element I need to add and remove this attribute depending on the boolean.
I already tried this code and it is working fine, is there any way to make it using vuejs directives?
HTML:
<div my-custom-attribute="my_element">
...
</div>
JS:
const el = document.getElementById("some_id");
if(my_bool) {
el.setAttribute("my-custom-attribute", "#my-element");
} else {
el.removeAttribute("my-custom-attribute")
}
You can register a directive as global using the below example, it provides you three lifecycle hooks for you to control the behavior, read the following and try to implement. Let us know if any problem occurs with your implementation and start a separate thread
https://v2.vuejs.org/v2/guide/custom-directive.html
Vue.directive('my-custom-directive', {
// When the bound element is inserted into the DOM...
inserted: function (el) {
// Focus the element
el.focus()
}
})

Polymer get the value from a paper input element

I have just started exploring polymer.js. I want to get name from paper-input element. It isn't working the alert is empty.
<dom-module id="hello-world">
<template>
<h1> Hello [[name]]</h1>
<paper-input value="{{name}}"></paper-input>
<button onClick="{{getData}}">Get data</button>
</template>
<script>
Polymer({
is: "hello-world",
properties: {
name: {
type: String,
value: '1'
}
},
getData: function () {
alert(this.name);
}
})
</script>
If you want onClick event, use on-click="getData" in polymer template.
....To add event listeners to local DOM children, use on-event
annotations in your template. This often eliminates the need to give
an element an id solely for the purpose of binding an event listener.
Because the event name is specified using an HTML attribute, the event
name is always converted to lowercase. This is because HTML attribute
names are case insensitive. So specifying on-myEvent adds a listener
for myevent. The event handler name (for example, handleClick) is case
sensitive. To avoid confusion, always use lowercase event names.
DEMO

What is the meaning of this code in Javascript

I am newbie to Javascript, I have difficulties getting the meaning of this code properly. I would like to share my thought over the code,and I need your guidance to understand it correctly.
<body>
<form>
<input type="button" value="Click Me!" id="say_hi" />
</form>
<script type="text/javascript" src="js_event_01.js"></script>
</body>
function hi_and_bye() {
window.alert('Hi!');
window.alert('Bye!');
}
var hi_button = document.getElementById("say_hi");
hi_button.onclick = hi_and_bye;
My understanding: the event "onclick" calls the function "hi_and_bye" when ID is "get_alerts". Similarly this could be applied to any event, and I can give an id attribute to any element and that id would be responsible to make an accessible corresponding input element.
Your understanding is correct. You could give an id to any DOM element, not only inputs. Then using the getElementById you could retrieve a reference to this element.
In this example that's what you are doing:
// Get a reference to a DOM element that has id="say_hi"
var hi_button = document.getElementById("say_hi");
// subscribe to the onclick event handler of the DOM element we retrieved on
// the previous line and attach this handler to the hi_and_bye javascript function
hi_button.onclick = hi_and_bye;
I don't think that the body of the function itself requires any more explanation: it will just display 2 alerts once after the other when this function executes.

this, current context-when should I use in jQuery?

I am not very sure with the use of "this" [current context] in jquery.What I know is- it prevents the dom from searching all the elements, it just work on that current element, which improve performance[correct me if I am wrong].Also I am not sure when to use this and when not.
lets say, should I go for
$("span",this).slice(5).css("display", "none")
or
$("span").slice(5).css("display", "none")
both will work, but I am not very clear as how really it works.can somebody explain it with a diff/proper example, and when to use what?
[EDIT]
$(function() {
$("#clickme").click(function() {
$("span",this).slice(5).css('display', 'block');//doesn't work ? why?
$("span").slice(5).css('display', 'block');//works..why?
});
});
enter code here <span id="clickme">Click me</span>
<span>itam1</sapn>
<span>itam2</sapn>
<span>itam3</sapn>
<span>itam4</sapn>
<span>itam5</sapn>
...upto10
Usually you can use the this keyword on event handlers since it will be a reference to the element that triggered the event and other jQuery functions like $.each.
For example when handling a click event lets say:
$('.parentElement').click(function () {
$('.foo', this).hide();
});
The above code, will hide all the elements with class foo that are descendants of the currently parentElement that was clicked.
The use of the context argument of the jQuery function is the equivalent of making a call to the find method:
$(expr, context);
// is just equivalent to:
$(content).find(expr);
EDIT: Looking at your example:
$("#clickme").click(function() {
$("span",this);//... (1)
$("span");//.. (2)
});
The first line, will look for all the span elements that are inside of #clickme (its descendants), since that element was the one that triggered the click event.
The second line, will look for all the span elements on the whole page.
How it works
Lets use this HTML for the examples:
<div id="container">
<div class="column">Link 1</div>
<div class="column">Link 2</div>
</div>
<div id="footer">
Link 3Link 3
</div>
The scoping parameter of the jQuery function should only be used if you already have a cached reference to a DOM element or jQuery wrapped element set:
var $set = $('#container');
$('a', $set).hide(); // Hides all 'a' tag descendants of #container
Or in an event:
$("#container").click(function(e){
$('a', this).hide(); // Same as call above
}
But it makes no sense to use it like this:
$('a', '#container').hide()
When it should be written like this:
$('#container a').hide();
Having said all that, it is generally cleaner and clearer to just use .find() instead of using the second parameter in the jQuery function if you already have the jQuery or DOM element. The first example I gave would be written this way instead:
var $set = $('#container');
$set.find('a').hide(); // Hides all 'a' tag descendants of #container
If this one call was the only reason you grabbed the #container object, you could also write it this way since it will still scope the search to the #container element:
$("#container a").hide(); // This is the same as $('a', "#container");
Why would you scope your selections
When jQuery looks for an unscoped selector, it will search through the entire document. Depending on the complexity of the selector, this could require a lot of searching. If you know that the element you are looking for only occurs within a specific parent, it will really speed up your code to scope the selection to that parent.
Regardless of what method of scoping you choose, you should always scope your selectors whenever possible.

Categories

Resources