I have some Polymer elements that are not inside an element/app, and I can't figure out how to attach their event handlers, such as on-click, to a global javascript function.
For example, let's say my code looks something like this
<head>
// Import stuff...
function login(){
// Do stuff
}
</head>
<body unresolved>
<dom-if id="signInItem">
<template>
<paper-button on-tap="login"><iron-icon icon="icons:account-circle"></iron-icon> Log in</paper-button>
</template>
</dom-if>
</body>
This won't work, because on-tap expects to bind to a property of an enclosing element (I guess). What are my options?
give some id for paper-button
<paper-button id="button"></paper-button>
in javascript you can add eventlistener as shown below
this.$.button.addEventListener('click', e => {
console.log("clicked");
// write your code
});
or you can write your code in seperate function
ready() {
super.ready();
this.$.button.addEventListener('click', e => this.handleClick(e));
}
handleClick(e) {
console.log(e);
}
If you like to fire a function not in polymer you may call;
this.dispatchEvent(new CustomEvent('login', { bubbles: true, composed: true, detail: true }));
This will fire your login listen in global js (ie. main.js) as below;
addEventListener('login', function (e) {
// Do something for login
})
EDIT: I think you also need to change dom-if to dom-bind in order to bind this code as its at root level
You can always forward a call to a local class member function (MyElement.login) to a global namespace:
/* 1 */ class MyElement extends Polymer.Element {
/* 2 */ // ...
/* 3 */
/* 4 */ login: (() => (evt) (MyGlobalNamespace || window).login.bind(this))()
/* 5 */ }
You can even omit the surrounding closure function - if you're not using this within the implementation of login -, simplifying line 4 to: login: (MyGlobalNamespace || window).login
Related
I need help by transferring data between two sibling elements of the polymer app. I can't make one of them to be the parent so that I can use dispatchEvent for the transfer of these elements.
Is there any way to transfer data between two sibling elements in polymer?
Of course, for example you can use DataBinding:
<some-element param="{{value}}"></some-element>
<another-element param="{{value}}"></another-element>
In these elements you can change this "value" param and it will be changed in another one:
<script>
class ...
changeParam(){
this.param="newValue";
}
</script>
Another way is using events. But you don't need to dispatch it. For example:
class ....
static get properties(){
return {
prop:{
type: Object,
value: {},
notify: true // (*)
}
}
In line with * you can see notify property. It fires event "prop-changed" when, as you could figure out, prop changes. So you can addEventListener for this event.
Note: somePropertyWhichCanBeChanged changes to some-property-which-can-be-changed-changed event.
My code:
<my-view1 name="view1" param="{{value}}"></my-view1>
<my-view2 name="view2" param="{{value}}"></my-view2>
VIEW1:
static get properties(){
return {
eventValue: {
type: String,
value: "Mirza",
notify: true
}
}
}
changeParam(){
this.param = "Azrim";
this.eventValue = "Mirzoni";
console.log("Param in view1: " + this.param);
console.log("EventValue in view1: " + this.eventValue);
}
VIEW2:
static get is() { return 'my-view2'; }
seeParam(){
console.log("Param in view2: " + this.param);
this.addEventListener('event-value-changed', function(e){
console.log("Receiving value...");
});
}
this is the function that I want to execute and is in app.component.ts
public goLocalization() :void {
this.localizationService.getLocalizationHttp().then(response => {
localStorage.setItem("locatios", JSON.stringify(response));
});
console.log('goLocalization');
}
from here I'm making the call, but it does not execute and it makes an error
<body onLoad="setInterval('goLocalization()',1000);"></body>
This is the error
Uncaught ReferenceError: goLocalization is not defined
at <anonymous>:1:1
In the Angular world events are captured using parenthesis. You can capture the load event like you have it but it will require curly braces {{}} to recieve the component context.
The ideal option is to wrap the event name in parenthesis and remove the 'on' text.
<body onLoad="{{setInterval('goLocalization()',1000);}}"></body>
or
<body (load)="setInterval('goLocalization()',1000);"></body>
maybe?
<body [onLoad]="setInterval('goLocalization()',1000);"></body>
body.onLoad will be executed out of angular context, so it can't see goLocalization
What you really should do is
inject your service in root component
choose appropriate life cycle stage (on init, on after content init, etc.)
add it(life cycle interface and method) to your root component (aka AppComponent) and call setInterval with goLocalization there
I could find a solution using the OnInit interface and the ngOnInit (){}
in the method I put the following code
ngOnInit () {
setInterval(() => {
this.goLocalization();
}, 1000);
}
Proper usage of the Polymer 1.0 element <iron-meta> is confusing. Here is the link on Github. And here is the link to the Polymer demo site.
Can someone please provide a proper code example of how to make it work?
This is the code I have so far.
<dom-module id="generic-element">
<style>...</style>
<template>
<iron-meta id="meta" key="info" value="foo/bar"></iron-meta>
The <code>value</code> stored at <code>key="info"</code> is <code><span>{{test}}</span></code>.
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'generic-element',
properties: {
test: {
value: function(){
return "Hello world"; // This is the only thing I can get to work so far.
// return (new Polymer.IronMetaQuery({key: 'info'}).value); // Doesn't totally break.
// All my other below attempts totally fail. Everything breaks.
// return this.$.meta.IronMetaQuery({key: 'info'}).value;
// return this.IronMetaQuery({key: 'info'}).value;
// return this.$.meta.byKey('info').getAttribute('value');
// return this.$.meta.byKey('info').value;
}
}
}
});
})();
</script>
Here is the Github link to the issue. And here is a Github repository that contains the complete problem code in context of the complete web app.
The issue with your code is that you are trying to set your element property's default value to something that's declared inside that same element's template itself. Two of the things that happen between the time when the element is created and when that element is attached include a) properties' default values are set; and b) the template undergoes preparations to be stamped into DOM. These tasks happen asynchronously so in essence you are generating a race condition.
Try setting your test default value inside the ready() callback - the ready() callback guarantees that DOM is ready to be accessed, which in your case is exactly where you declared your <iron-meta> key.
<dom-module id="generic-element">
<style>...</style>
<template>
<iron-meta id="meta" key="info" value="foo/bar"></iron-meta>
The <code>value</code> stored at <code>key="info"</code> is <code><span>{{test}}</span></code>.
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'generic-element',
properties: {
test: String
},
ready: function () {
// this will work
this.test = this.$.meta.byKey("info");
}
});
})();
</script>
jsbin: http://jsbin.com/vosekiwehu/edit?html,output
I am using the code-mirror component from the Polymer Designer, and can set the initial value, but cannot see how to get changes to the code from the user.
I initialise the code-mirror using
<code-mirror id="code_mirror" value="{{code}}">
</code-mirror>
and would like to listen for changes in {{code}}, but codeChanged doesn't seem to fire.
I know I can get the actual value using code_mirror.$.mirror.getValue(), but would like to use data-binding.
I have tried using on-change to no avail.
Assuming you're using https://github.com/PolymerLabs/code-mirror what you need to do is make the CodeMirror instance created in the ready handle some events that the instance itself is emitting, then make the code-mirror element fire any custom event (something which I know is called event relay)
The following example makes the polymer element fire the custom event code-change whenever the editor value is changed
ready: function() {
var me = this;
//...
this.mirror = CodeMirror(this.shadowRoot, { /* ... */ });
this.mirror.on('change', function () {
// me = polymer instance
me.fire('code-change', { value: me.mirror.getValue() })
});
}
Then any instance of the polymer custom element would need to listen to that event using Polymer's declarative event mapping or through addEventListener
1st case (if code-mirror is inside another <polymer-element />):
<code-mirror on-code-change="{{ onCodeChange }}"></code-mirror>
// ...
<script>
Polymer({
onCodeChange: function(event, detail, sender) { ... }
});
</script>
2nd case ():
<code-mirror></code-mirror>
<script>
document
.querySelector('code-mirror')
.addEventListener('code-change', function () { ... });
</script>
I need your help.
I have a directive with a function parameter ( scope: { myParam: '#'}). And I'm passing the parameters in HTML, like my-param="myFunc(param1, param2)"
This works perfectly. But, I need to inject the event object in to the parameters. Does some one know how can I do that?
I tried $provider.annotate and $provider.instantiate, but they did not work because it's taking the reference function in directive. ($a in my case), so it can't get the function arguments.
any idea?
When you're calling a function created by the & isolate scope syntax, you can pass parameters to it as a named map. If your directive is defined like this:
scope: { myParam: '&' },
link: function (scope, el) {
el.on('click', function (e) {
scope.myParam({$event: e});
});
}
and used like this:
<my-directive my-param="console.log($event)"></my-directive>
... you should see the desired behavior.
chrisrhoden's answer is great. I would suggest to expand upon it a bit with the following. Doing so will help prevent ng-click double-firing issues relating to mobile devices and/or AngularJS conflicts with jQuery.
myApp.directive('responsiveClick', function(){
return {
scope: { myCb: '&' },
link: function (scope, el,attr) {
el.bind('touchstart click', function (e) {
e.preventDefault();
e.stopPropagation();
scope.myCb({$event: e});
});
}
}
});
along with the markup as follows:
<a class="mdi-navigation-cancel" my-cb="removeBasketItem($event,item)" responsive-click></a>
have you tried passing it in the original function?
my-param="myFunc($event, param1, param2)"