How to unbind property in Polymer 1.0 - javascript

In Polymer 1.0 we can bind an element property to a variable:
<paper-textarea id='area' value={{some_variable}}></paper-textarea>
How can I unbind it?
Below is a solution that doesn't works for me. When some_variable changes it updates area value.
this.$.area.value = "foo";

You can't dynamically bind and/or unbind to element attributes in Polymer 1.0, because bindings are baked during element registration time, not during created/ready/attached. Ref Binding imperatively
Honestly I'm not exactly sure what your use-case is; however, it highly likely that you can achieve it by a) binding your value attribute to a computed function; or b) bind to a dummy variable
<paper-textarea id='area' value={{letsCompute(some_variable)}}></paper-textarea>
...
letsCompute: function (v) {
//return your logic to bind or unbind
},
...

It is not 100% clear what you are trying to achieve, but with Polymer you can do one-way data binding.
Downward binding:
<script>
Polymer({
is: 'custom-element',
properties: {
prop: String // no notify:true!
}
});
</script>
...
<!-- changes to "value" propagate downward to "prop" on child -->
<!-- changes to "prop" are not notified to host due to notify:falsey -->
<custom-element prop="{{value}}"></custom-element>
Upwards binding:
<script>
Polymer({
is: 'custom-element',
properties: {
prop: {
type: String,
notify: true,
readOnly: true
}
}
});
</script>
...
<!-- changes to "value" are ignored by child due to readOnly:true -->
<!-- changes to "prop" propagate upward to "value" on host -->
<custom-element prop="{{value}}"></custom-element>
Check out the documentation for more information.

Related

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()
}
})

Late "manual" upgrading of an element towards a customized-built-in web component

I have a jQuery plugin (which I don't want to modify) that is dynamically creating a div. Aside from that, I have a webcomponent scrollable-div, which is a customized built-in extended from HTMLDivElement. As I have no control over how that div is created by the jQuery plugin, I need to upgrade it after creation and after it has already been added to the DOM.
class myDiv extends HTMLDivElement {
constructor(...args) {
const self = super(...args);
self.addEventListener('click', (e) => {
e.target.textContent = 'clicked'
})
return self;
}
}
customElements.define('my-div', myDiv, { extends: 'div' });
document.addEventListener('DOMContentLoaded', () => {
// this is where I'm trying to turn the div#upgradeMe into a my-div
upgradeMe.setAttribute('is', 'my-div');
});
<div id="upgradeMe">Click me</div>
Simply adding the is="my-div" attribute obviously does not do the trick, the div simply stays a regular HTMLDivElement. How can I programmatically upgrade a native element that is already in the DOM to a customized built-in web component?
It's not possible because the element is already created as a standard <div> element and not identified when parsed as upgradable (extendable) due to the lack of the is attribute.
If the custom element is already defined, the only possible workaround is to replace the existing by a clone (as suggested in the comments by #barbsan).
The short way:
create a <template> element
copy the div's outerHTML into its innerHTML property
replace the orginal element with the template's content with replaceChild()
class myDiv extends HTMLDivElement {
constructor(...args) {
const self = super(...args);
self.addEventListener('click', (e) => {
e.target.textContent = 'clicked'
})
return self;
}
}
customElements.define('my-div', myDiv, { extends: 'div' });
document.addEventListener('DOMContentLoaded', () => {
// this is where I'm trying to turn the div#upgradeMe into a my-div
upgradeMe.setAttribute('is', 'my-div');
var t = document.createElement( 'template' )
t.innerHTML = upgradeMe.outerHTML
upgradeMe.parentElement.replaceChild( t.content, upgradeMe )
});
<div id="upgradeMe">Click me</div>
Précisions
When an element is parsed, an is value is affected according to the DOM spec:
Elements have an associated namespace, namespace prefix, local name, custom element state, custom element definition, is value. When an element is created, all of these values are initialized.
Only elements with a valid is attribute are identified as customizable:
An element’s custom element state is one of "undefined", "failed", "uncustomized", or "custom". An element whose custom element state is "uncustomized" or "custom" is said to be defined. An element whose custom element state is "custom" is said to be custom.
Therefore if the element has no is attribute at parse time, it will not be customizable. That's why you cannot add the is attribute afterward.
Also in the HTML specs:
After a custom element is created, changing the value of the is attribute does not change the element's behavior, as it is saved on the element as its is value.
The is attribute is used only at element creation (at parse time) to initialize the is value and has no effect if changed when the element is already created. In that sense is value is read-only.
If you want to support all modern browser's you can't customize built in components, Apple said they will never support is="" https://github.com/w3c/webcomponents/issues/509#issuecomment-222860736

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

Accessing element attributes before Polymer element registration

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');

How do I call jQuery's hide() method in Ember.js?

I am trying to hide an object using the jQuery method hide(), but it doesn't work.
I used console.log() to check the value of the argument in called function, so I know Im not doing right. But, i dont know how to make it work...
Here's what I have:
#------------------------Model------------------------
App.Monster = Ember.Object.extend({
name: "",
hp: 0,
isDead : false,
isDeadChanged: function(target, value){
App.monstersController.kill(target);
}.observes('isDead')
});
#------------------------Controller------------------------
App.monstersController = Ember.ArrayProxy.create({
content:[],
createMonster: function(name,hp){
var monster = App.Monster.create({name:name});
this.pushObject(monster);
},
kill: function(target){
//I Want the selected object to hide by using Jquery hide method!!
$('target').hide();
this.removeObject(target);
},
#------------------------HTML FILE------------------------
{{#each App.monstersController contentBinding="App.monstersController.content" tagName="ul"}}
<li>
{{view Ember.Checkbox checkedBinding="isDead"}}
<label for="" {{bindAttr class="isDead"}}>{{name}}</label>
</li>
{{/each}}
Generally bringing your DOM scripting patterns to Ember isn't going work, since Ember isn't about DOM manipulation it's about describing your application using objects. The DOM representation of your application will update automatically to reflect the state of its underlying data objects.
Ember.View tracks its visibility (and the visibility of its child views) with the isVisible property and will handle toggling the it's DOM representation for you. You should try to uncover the semantic object meaning of visibility for a given view context. For example, if you decided finished items in a todo list shouldn't be visible, you'd do:
{{#each item in controller}}
{{view App.TodoItemView isVisibileBinding="item.isComplete"}} <a {{action kill item}}>Done!</a>
{{/each}}
Don't quote target.
kill: function(target){
//I Want the selected object to hide by using Jquery hide method!!
$(target).hide();
this.removeObject(target);
},
$('target') looks for <target> elements.

Categories

Resources