Polymer 2 - display one element when click on another - javascript

I have used Polymer 2 to create two custom elements:
a button
a overlay element
i am importing and using them both on another "main element".
What i would like to do is to toggle a class on the "overlay element" with each "button" click.
Is it possible to do this? Can i share data-bindings between elements?

Using the adage "events up, props down," sibling elements share data through their parent. There are various solutions for this. I'm using Redux to share data across several elements, but simple parent-to-n-children approach works:
In main-element.html
<button-element id="button"></button-element>
<overlay-element id="overlay"></overlay-element>
...
ready() {
super.ready();
this.$.button.addEventListener('toggle', this._onUpdate);
}
_onUpdate(event) {
this.$.overlay.toggle = !this.$.overlay.toggle;
}
In button-element.html
<button on-click="_doClick">Ok</button>
...
_doClick(event) {
this.dispatchEvent(new CustomEvent('toggle'));
}
In overlay-element.html
<div>[[status]]</div>
...
static get properties() {
return {
toggle: {
type: Boolean,
observer: '_toggleChanged'
},
status: {
type: String
}
...
_toggleChanged(newValue, oldValue) {
this.status = newValue ? 'I\'m hit.' : 'Missed me.';
}
See this pen.

Related

Can i insert IF statements in Kendo Dialog actions?

I'm trying to make a Kendo dialog pop-up. But i need to hide a button under a certain condition. Can i make an if statement somewhere in actions property or is there any other way to hide them from outside?
I know that you can do whatever in content property, but i was wondering if i can customize existing buttons. This is how i theoretically imagined it but it didn't work
actions: [{
if(link !=null) {
text: linkName,
action: function (e) {
window.location = link;
return true;
},
}
}, {
text: 'Закрыть',
action: function (e) {
Close();
return true;
}
}]
As briosheje said, you have to define array before rendering the widget, but you can update existing dialog's actions with setOptions method. You can check a basic example at https://dojo.telerik.com/EJefarON/8

Debounced from Polymer properties observer appears to fail

If I call a Polymer debouncer from a button click it works perfectly. I click 5 times in less than 2 seconds, prints only one timestamp:
myProofOfConcept(){
this.__debouncer = Polymer.Debouncer.debounce(
.__debouncer,
Polymer.Async.timeOut.after(2000),
() => {
console.log("HEY " + Date.now());
});
}
But if I call the exact same method from a Polymer properties change observer, it will wait the required 2 second timeout, and then console print as many times as the observer calls it, even if only 1 millisecond apart.
Is there some external factor that I don’t know about, that is driving this difference in behavior?
Here's something to look for if this ever happens to you.
If you debounce a method within a web component...
and then you instantiate multiple instances of that component within your web app... it may appear to you that the debouncer is not working, when in fact it may be working, rather it is just working in multiple instances of the same web component.
I had a stray previous instance of the web component inside an entirely different page. Hadn't been used, or even noticed. I had just forgotten to remove it when I migrated it to a different page.
EDIT: Control for debouncing across all instances of the element and for property changed from multiple places (button clicks and setInterval).
Usage seems to be fine when applied like:
<dom-module id="my-element">
<template>
<style>
:host {
display: block;
}
</style>
[[prop]]
<button on-click="add">Test</button>
</template>
<script>
(function() {
let DEBOUNCED_METHOD;
HTMLImports.whenReady(function() {
class MyElement extends Polymer.Element {
static get is() { return 'my-element'; }
static get properties() {
return {
prop: {
value: 0,
type: Number,
observer: 'myProofOfConcept'
}
}
}
constructor() {
super();
let test = setInterval(() => {
this.add();
}, 400);
setTimeout(() => {
clearInterval(test);
}, 4500)
}
add() {
this.prop += 1;
}
myProofOfConcept(){
DEBOUNCED_METHOD = Polymer.Debouncer.debounce(
DEBOUNCED_METHOD,
Polymer.Async.timeOut.after(2000),
this.log);
}
log() {
console.log("HEY " + Date.now());
}
}
customElements.define(MyElement.is, MyElement);
});
}())
</script>
Hope that helps!

Extending every html element

With x-tag I am trying to find a way to extend every html element that I put is:"ajax-pop" attribute.
What I want to do is when I click an element with is:"ajax-pop" attribute I will do some dynamic ajax loads. It will be a good starting point for me to develop a manageble system.
I know I can do it with some different ways but I am wondering is there a way to do it like this way extends:'every single native html element'
xtag.register('ajax-pop', {
extends: 'WHAT SHOULD I WRITE HERE???',
lifecycle: {
created: function () {
},
inserted: function () {
},
removed: function () { },
attributeChanged: function () { }
},
methods: {
someMethod: function () { }
},
accessors: {
popUrp: {
attribute: {
name: "pop-url"
}
},
},
events: {
tap: function () { },
focus: function () { }
}
});
Type extensions must be defined element by element. A single custom element cannot extend multiple standard elements.
For, each custom element owns it own prototype, that can't be reused.
If you want to extend a button (for example), you have to write in JavaScript :
xtag.register('ajax-pop', {
extends: 'button',
...
And, in the HTML page:
<button is="ajax-pop">
...
You can do this using x-tag's delegate pseudo, and by adding a data- attribute to elements you wish to have this behavior:
<article data-pop="/path/to/content.html"></article>
And your JavaScript would be something like this:
xtag.addEvent(document.body, 'tap:delegate([data-pop])', function (e) {
var uri = this.getAttribute('data-pop');
$.get(uri).done(function (res) {
this.innerHTML = res;
}.bind(this));
});
Here's a codepen example:
http://codepen.io/jpecor-pmi/pen/Vexqyg
I believe you're going about using x-tag the wrong way. X-tag is meant to be used to implement entirely new tags; what you're trying to do is simply modify different pre-existing DOM elements. This can easily be done in pure javascript or more easily in jquery by assigning each desired element a shared class.

How to show drop menu and hide others in React.js

I just want to know the best way to proceed (don´t need the code, just the way to do it). I´m trying to show a dropdown menu when I click on it´s LI element.
var Balloon = React.createClass({displayName: "Balloon",
getInitialState: function() {
return { shaded: false };
},
handleClick: function(event) {
this.setState({ shaded: !this.state.shaded });
},
render: function() {
var panel = this.state.shaded ? React.createElement(BalloonPanel, {type: this.props.type, data: this.props.data}) : "";
return (
React.createElement("li", {onClick: this.handleClick},
React.createElement("a", {href: ""}),
React.createElement("div", {hidden: true}),
React.createElement("div", null,
React.createElement("div", {class: "triangle"}, " "),
panel
)
)
);
}
});
Here is the complete code:
Thanks in advance.
So assuming your drop downs are all reliant upon one another, i.e.. when you click one the others close etc... than they should all be built with the same object and ascribe to a click event that passes this to the parent.
var ParentComponent = React.createClass({
clicked: function () {
alert("you clicked me");
},
return: function () {
render (
<ReactListChild onClick={this.props.clicked.bind(this)} />
)
});
Keep in mind you need to use the bind method in order for the children to know which one was clicked (to take the appropriate action)
So summing this up, your parent component should have a state variable saying which one to show and set some sort of variable, possibly give it the name of the element or something. that way if that element is not listed as shown in state the others will remain closed.
fyi, I did not test this code, it's just a rough idea. Most likely you will do some sort of for loop to render many of these child elements. Remember the bind, or you'll get burned.

Backbone events are firing multiple times after re-rendering sub-views

We have a single Backbone view comprised of a sidebar and several sub-views. For simplicity, we've decided to have the sidebar and sub-views governed by a single render function. However, the click .edit event seems to be firing multiple times after clicking on one of the sidebar items. For example, if I start out on "general" and click .edit, then hello fires once. If I then click .profile on the sidebar and click .edit again, hello fires twice. Any ideas?
View
events: {
"click .general": "general",
"click .profile": "profile",
"click .edit": "hello",
},
general: function() {
app.router.navigate("/account/general", {trigger: true});
},
profile: function() {
app.router.navigate("/account/profile", {trigger: true});
},
render: function(section) {
$(this.el).html(getHTML("#account-template", {}));
this.$("#sidebar").html(getHTML("#account-sidebar-template", {}));
this.$("#sidebar div").removeClass("active");
switch (this.options.section) {
case "profile":
this.$("#sidebar .profile").addClass("active");
this.$("#content").html(getHTML("#account-profile-template"));
break;
default:
this.$("#sidebar .general").addClass("active");
this.$("#content").html(getHTML("#account-general-template"));
}
},
hello: function() {
console.log("Hello world.");
},
Router
account: function(section) {
if (section) {
var section = section.toLowerCase();
}
app.view = new AccountView({model: app.user, section: section});
},
Solution
My solution was to change the router to this:
account: function(section) {
if (section) {
var section = section.toLowerCase();
}
if (app.view) {
app.view.undelegateEvents();
}
app.view = new AccountView({model: app.user, section: section});
},
This works for now, but will this create a memory leak?
I had exactly the same problem when I first started using backbone. Like Peter says, the problem is that you have more than one instance of the View being created and listening for the event. To solve this, I created this solution in my last backbone project:
/* Router view functions */
showContact:function () {
require([
'views/contact'
], $.proxy(function (ContactView) {
this.setCurrentView(ContactView).render();
}, this));
},
showBlog:function () {
require([
'views/blog'
], $.proxy(function (BlogView) {
this.setCurrentView(BlogView).render();
}, this));
},
/* Utility functions */
setCurrentView:function (view) {
if (view != this._currentView) {
if (this._currentView != null && this._currentView.remove != null) {
this._currentView.remove();
}
this._currentView = new view();
}
return this._currentView;
}
As you can see, it's always removing the last view and creating a new one, which then renders. I also add a require statement in the router because I don't want to have to load all views in the router until they are actually needed. Good luck.
Sounds like you are attaching multiple view instances to the same DOM element and they are all responding to the events. Are you making a new view each time you navigate without removing the previous view?
I have a dynamic view, that renders different templates inside the same element (about 12), based on router params. Now, the container in which the view renders, is defined inside the view.render() like so "el: '#some-container'". Naturally, i have to remove the view if it exists, before creating a new or the same one, to prevent zombies and s#!t. Just as a reminder, calling view.remove(), actually removes '#some-container' from the DOM, meaning the view has no place to render in, except for the first time. Now, there are dozens of methods to prevent this from happening. Just thought i should share in case anyone needs to save a few hours of research.

Categories