I am trying to use iron-meta to manage state in a Polymer app. Here is my Plunker demo.
On that same Plunker, I am also using Mixins to manage state. (So we can compare the two systems.)
Desired Behavior
On the demo, at the bottom, I expect the part that follows "Meta says:" to match and track the part that follows "Send notifications option is:" when the options checkbox at the top labeled "Send Notifications" is clicked.
Actual Behavior
But instead of that desired behavior, the actual behavior I get is the "Meta says:" section never populates with any data.
Demo
Plunker Demo
Demo screen recording
my-view2.html
<link rel="import" href="my-options.html">
<base href="https://polygit.org/polymer+v2.0.0/shadycss+webcomponents+1.0.0/components/">
<link rel="import" href="polymer/polymer-element.html">
<link rel="import" href="iron-meta/iron-meta.html">
<dom-module id="my-view2">
<template>
<style>
:host {
display: block;
padding: 10px;
}
</style>
<iron-meta key="meta" value="{{meta}}"></iron-meta>
<my-options></my-options>
<div class="card">
<div class="circle">2</div>
<h1>View Two</h1>
<p>Ea duis bonorum nec, falli paulo aliquid ei eum.</p>
<p>Id nam odio natum malorum, tibique copiosae expetenda mel ea.Detracto suavitate repudiandae no eum. Id adhuc minim soluta nam.Id nam odio natum malorum, tibique copiosae expetenda mel ea.</p>
<p>Send notifications option is: <b>[[ options.subscribe ]]</b></p>
<p>Meta says: <b>[[ meta ]]</b></p>
</div>
</template>
<script>
class MyView2 extends MyOptionsMixin(Polymer.Element) {
static get is() {
return 'my-view2';
}
}
window.customElements.define(MyView2.is, MyView2);
</script>
</dom-module>
my-options.html
<base href="https://polygit.org/polymer+v2.0.0/shadycss+webcomponents+1.0.0/components/">
<link rel="import" href="polymer/polymer-element.html">
<link rel="import" href="paper-checkbox/paper-checkbox.html">
<link rel="import" href="iron-meta/iron-meta.html">
<dom-module id="my-options">
<template>
<style>
:host {
display: block;
padding: 16px;
}
h3, p {
margin: 8px 0;
}
</style>
<iron-meta key="meta" value="[[options.subscribe]]"></iron-meta>
<h3>Options</h3>
<p>
<paper-checkbox checked="{{ options.subscribe }}">Send Notifications</paper-checkbox>
</p>
</template>
<script>
(function() {
let optionsInstance = null;
class MyOptions extends Polymer.Element {
static get is() { return 'my-options'; }
static get properties() {
return {
options: {
type: Object,
value: () => ({
subscribe: false
})
},
subscribers: {
type: Array,
value: () => []
}
}
}
static get observers() {
return [
'optionsChanged(options.*)'
]
}
constructor() {
super();
if (!optionsInstance) optionsInstance = this;
}
register(subscriber) {
this.subscribers.push(subscriber);
subscriber.options = this.options;
subscriber.notifyPath('options');
}
unregister(subscriber) {
var i = this.subscribers.indexOf(subscriber);
if (i > -1) this.subscribers.splice(i, 1)
}
optionsChanged(change) {
for(var i = 0; i < this.subscribers.length; i++) {
this.subscribers[i].notifyPath(change.path);
}
}
}
window.customElements.define(MyOptions.is, MyOptions);
MyOptionsMixin = (superClass) => {
return class extends superClass {
static get properties() {
return {
options: {
type: Object
}
}
}
connectedCallback() {
super.connectedCallback();
optionsInstance.register(this);
}
disconnectedCallback() {
super.disconnectedCallback();
optionsInstance.unregister(this);
}
}
}
}());
</script>
</dom-module>
The short answer is: <iron-meta> doesn't have notification support.
https://github.com/PolymerElements/iron-meta/issues/9
Your example is relying on the fact the two-way bindings work and your meta property gets updated when the observed key changes. This is not the case. Internally, values are simply assigned to a global store, and there is not publish/subscribe mechanism in-place.
https://github.com/PolymerElements/iron-meta/blob/master/iron-meta.html#L91
If you're using Polymer 1.x, maybe this element will satisfy your needs:
https://www.webcomponents.org/element/trofrigo/global-variable
Related
I would like to pass the id of the selected grid using app-router. Somehow I seem to be missing a link. I want to be able to pass the id of the selected row from the grid and use that value in the iron-ajax url http://192.168.178.31:8080/demo/questions?assessmentId=TEST in place if assessmentId.
my-data.html
<dom-module id="my-data">
<template>
<style include="shared-styles">
:host {
display: block;
padding: 10px;
}
.title {
margin-left: 40%;
}
.card {
height: 100%;
}
</style>
<div class="card">
<div class="title">ASSESSMENTS</div>
<!-- Fetch an array of users to be shown in the grid -->
<vaadin-grid id="material" items="{{assessments}}" selected-items={{selectedItems}} active-item="{{selectedItem}}">
<vaadin-grid-selection-column auto-select frozen>
</vaadin-grid-selection-column>
<vaadin-grid-column>
<template class="header">Assessment Id</template>
<template>[[item.assessmentId]]</template>
</vaadin-grid-column>
<vaadin-grid-column>
<template class="header">Assessment Topic</template>
<template>[[item.assessmentTopic]]</template>
</vaadin-grid-column>
<vaadin-grid-column>
<template class="header">Assessment Subtopic</template>
<template>[[item.assessmentSubtopic]]</template>
</vaadin-grid-column>
<vaadin-grid-column>
<template class="header">Created By</template>
<template>[[item.createdBy]]</template>
</vaadin-grid-column>
<vaadin-grid-column>
<template class="header">Rating</template>
<template>[[item.rating]]</template>
</vaadin-grid-column>
</vaadin-grid>
<app-location route="{{route}}" url-space-regex="^[[rootPath]]">
</app-location>
<app-route route="{{route}}"
pattern="[[rootPath]]:page"
data="{{routeData}}"
tail="{{subroute}}">
</app-route>
<iron-selector selected="[[page]]" attr-for-selected="name" class="drawer-list" role="navigation">
<a name="assessment" href="[[rootPath]]assessment">Quiz Page</a>
</iron-selector>
</div>
</template>
<script>
class MyData extends Polymer.Element {
static get is() { return 'my-data'; }
static get properties() {
return {
index: {
type: Number,
value: 0
},
assessments: {
type: Array,
observer: 'isAssessmentLoaded'
},
selectedItem: {
type: Array,
},
selectedItems: {
type: Array,
},
page: {
type: String,
reflectToAttribute: true,
observer: '_pageChanged',
},
routeData: Object,
subroute: String,
// This shouldn't be neccessary, but the Analyzer isn't picking up
// Polymer.Element#rootPath
rootPath: String,
};
}
constructor() {
super();
}
_selectedItemsChanged(selectedItem, selectedItems) {
console.log(selectedItems);
this.selectedItem = selectedItem;
}
isAssessmentLoaded(q) {
if (q) {
console.log('loaded questions', q); // questions are loaded.
}
}
redirect() {
page('/')
}
static get observers() {
return [
//'_routePageChanged(routeData.page)',
'_selectedItemsChanged(selectedItem, selectedItems)'
];
}
// _routePageChanged(page) {
// // If no page was found in the route data, page will be an empty string.
// // Default to 'assessments' in that case.
// this.page = page | 'assessment';
// // Close a non-persistent drawer when the page & route are changed.
// // if (!this.$.drawer.persistent) {
// // this.$.drawer.close();
// // }
// }
// _pageChanged(page) {
// // Load page import on demand. Show 404 page if fails
// var resolvedPageUrl = this.resolveUrl('my-' + page + '.html');
// Polymer.importHref(
// resolvedPageUrl,
// null,
// this._showPage404.bind(this),
// true);
// }
_showPage404() {
this.page = 'view404';
}
}
window.customElements.define(MyData.is, MyData);
</script>
</dom-module>
my-assessment.html
<dom-module id="my-assessment">
<template>
<style include="shared-styles">
:host {
display: block;
padding: 10px;
}
</style>
<!--Check the url is correct ! And last responce property should be {{}} instead [[]] (as up way data binding) -->
<iron-ajax
id="requestRepos"
url="http://192.168.178.31:8080/demo/questions?assessmentId=TEST"
handle-as="json"
last-response="{{repos}}">
</iron-ajax>
<template is="dom-if" if="{{repos}}">
<my-quiz repos= "{{repos}}"></my-quiz>
</template>
</template>
<script>
class Assessment extends Polymer.Element {
static get is() { return 'my-assessment'; }
constructor() {
super();
}
ready() {
super.ready();
this.$.requestRepos.generateRequest();
}
}
window.customElements.define(Assessment.is, Assessment);
</script>
</dom-module>
Here is how to change the route by clicking on the link:
<app-location
route="{{route}}"
use-hash-as-path="">
</app-location>
<app-route
route="{{route}}"
pattern="/:page"
data="{{routeData}}"
tail="{{subroute}}">
</app-route>
<a name="some_name" href="#/some_route">Change route</a>
Problem
I have started upgrading my polymer PWA to version 2.0 of polymer. There is a suggestion in docs to upgrade the big project to polymer 1.8 version and elements to 2.0 hybrid style. I am doing the same but i got following error
Uncaught TypeError: Class extends value undefined is not a constructor or null
can someone help me solve this please,Also i don't get what's meant by hybrid style of element whether it's 2.0 or something else?
Thanks in advance.
My element (updated)
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-material/paper-material.html">
<dom-module id="account-analytics">
<template>
<style >
.flex{
display: flex;
width: 100%;
align-items: center;
}
.flexChild{
flex-grow: 1;
text-align: center;
flex-basis: 40px;
}
</style>
<iron-ajax auto
id="accountAnalytics"
url="/napi/accountanalytics"
handle-as="json"
last-response="{{analytics}}"
loading="{{analyticsLoading}}"
debounce-duration="1000">
</iron-ajax>
<div style="font-size: 25px;font-weight: bold;display: none;padding-top: 2%;padding-left: 2%;padding-bottom: 2%" id="analyticsHead">eGlu Today</div>
<div class="flex">
<div class="flexChild"><b>Rules</b></div>
<div class="flexChild"><b>Scenes</b></div>
<div class="flexChild"> <i class="material-icons">linked_camera</i></div>
<div class="flexChild"><i class="material-icons">android</i></div>
<div class="flexChild"><img src="../../images/apple_logo_200px.jpeg" style="width: 30px;padding-bottom: 5px"></div>
</div>
<div class="flex">
<div class="flexChild">{{analytics.ruleCount}}</div>
<div class="flexChild">{{analytics.sceneCount}}</div>
<div class="flexChild">{{analytics.cameraCount}}</div>
<div class="flexChild">{{analytics.androidInstallations}}</div>
<div class="flexChild">{{analytics.iosInstallations}}</div>
</div>
</template>
</dom-module>
<script>
class accountAnalytics extends Polymer.Element{
static get is(){return 'account-analytics';}
static get properties(){
return{
hubId: {
type: String,
value: '7e-f2-ca-ab-40-34-34-95',
notify: true
},
analyticsLoading:{
type:Boolean,
notify:true
},
analytics:Object,
customerId:{
type:String,
value:'',
observer:'emailChanged'
},
integratorOptions:Boolean,
refreshCustomer:{
type:Boolean,
value:false,
notify:true,
observer:'_refreshCustomer'
}
};
}
constructor() {
super();
}
emailChanged() {
if(this.customerId=='')
this.$.analyticsHead.style.display='block';
this.fireAnalytics();
}
_refreshCustomer() {
this.fireAnalytics();
this.refreshCustomer=false;
}
ready(){
super.ready();
this.fireAnalytics();
}
fireAnalytics(){
if(this.customerId==undefined)
return;
var t= Date.now();
var p = this.getCookie('token');
this.$.accountAnalytics.headers={"token":p};
this.$.accountAnalytics.params={"customerId":this.customerId,"t":t};
// this.$.accountAnalytics.generateRequest();
}
getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
}
customElements.define(accountAnalytics.is, accountAnalytics);
</script>
I ran into a problem with polymer and app-storage when trying to remove an entry.
I'm trying to add a button to the Vaading Grid that will delete the entry on which the button is set.
The only thing is that I cannot seem to make it work, when I click the button, even console.log doesn't work. What am I doing wrong here?
Here is the code:
<!--
#license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../bower_components/polymer/polymer-element.html">
<link rel="import" href="shared-styles.html">
<link rel="import" href="../bower_components/vaadin-grid/vaadin-grid.html">
<link rel="import" href="../bower_components/vaadin-date-picker/vaadin-date-picker.html">
<link rel="import" href="../bower_components/paper-input/paper-input.html">
<link rel="import" href="../bower_components/paper-button/paper-button.html">
<link rel="import" href="../bower_components/app-storage/app-localstorage/app-localstorage-document.html">
<dom-module id="my-view1">
<template>
<style include="shared-styles">
:host {
display: block;
padding: 10px;
}
.form {
display: flex;
flex-direction: column;
}
.form paper-input {
flex: 1;
margin-right: 10px;
}
.form vaadin-date-picker {
flex: 1;
margin-top: 10px;
}
.form paper-button {
margin-top: 10px;
align-self: flex-end;
}
</style>
<div class="card">
<div class="form">
<paper-input label="Sum" value="{{todo.task}}" auto-validate placeholder="Suma" required=true pattern="[0-9]*" error-message="Numbers only"></paper-input>
<vaadin-date-picker label="When" value="{{todo.due}}"></vaadin-date-picker>
<paper-button raised on-tap="_addToDo">Add</paper-button>
</div>
<br>
<vaadin-grid items={{todos}}>
<vaadin-grid-column width="calc(50% - 100px)">
<template class="header">Sum</template>
<template>{{item.task}}</template>
</vaadin-grid-column>
<vaadin-grid-column width="calc(50% - 100px)">
<template class="header">When</template>
<template>{{item.due}}</template>
</vaadin-grid-column>
<vaadin-grid-column>
<template>
<div style="display: flex; justify-content: flex-end;">
<button on-tap="_remove">Remove</button>
</div>
</template>
</vaadin-grid-column>
</vaadin-grid>
</div>
<app-localstorage-document key="todos" data="{{todos}}">
</app-localstorage-document>
</template>
<script>
class MyView1 extends Polymer.Element {
static get is() { return 'my-view1'; }
static get properties() {
return {
todo: {
type: Object,
value: () => { return {} }
},
todos: {
type: Array,
value: () => []
}
};
}
_addToDo() {
this.push('todos', this.todo);
this.todo = {};
};
_remove() {
console.log("Clicked!");
};
}
window.customElements.define(MyView1.is, MyView1);
</script>
</dom-module>
So the _addToDo button is working, but not the _remove button. When I open the console, this is empty.
Please let me know what am I doing wrong here. Thank you!
Since button is native HTML Element on-tap will not work.
Change it to polymer element like paper-button or change on-tap to onclick.
Is it possible to have a single layer visible on the map in this ESRI tutorial LayerList widget ?
Each time you click on a layer, the previous one should deactivate. So you always have only one layer on the map.
Michelle
Updated answer with version 4 of the API.
It is possible to add the functionality at creating the widget using 2 features.
The listItemCreatedFunction function-
https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-LayerList.html#listItemCreatedFunction
According to the api:
Specifies a function that accesses each ListItem. Each list item can be modified according to its modifiable properties. Actions can be added to list items using the actionsSections property of the ListItem.
and the operationalItems property-
https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-LayerList.html#operationalItems
According to the api:
A collection of ListItems representing operational layers.
var LayerListWidget = new LayerList({
listItemCreatedFunction: (event) => {
var itemView = event.item; // layer-view of selection
itemView.watch("visible", (event) => {
LayerListWidget.operationalItems.forEach((layerView) => {
if (layerView.layer.id != itemView.layer.id) {
layerView.visible = false;
}
});
});
},
view: view,
});
I managed to write a code for you . Check it and let me know :
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
<title>Layer List Dijit</title>
<link rel="stylesheet" href="https://js.arcgis.com/3.20/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="https://js.arcgis.com/3.20/esri/css/esri.css">
<script language="javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<style>
html, body, .container, #map {
height:100%;
width:100%;
margin:0;
padding:0;
margin:0;
font-family: "Open Sans";
}
#map {
padding:0;
}
#layerListPane{
width:25%;
}
.esriLayer{
background-color: #fff;
}
.esriLayerList .esriList{
border-top:none;
}
.esriLayerList .esriTitle {
background-color: #fff;
border-bottom:none;
}
.esriLayerList .esriList ul{
background-color: #fff;
}
</style>
<script>var dojoConfig = { parseOnLoad: true };var busy=false;</script>
<script src="https://js.arcgis.com/3.20/"></script>
<script>
require([
"esri/arcgis/utils",
"esri/dijit/LayerList",
"dijit/layout/BorderContainer",
"dijit/layout/ContentPane",
"dojo/domReady!"
], function(
arcgisUtils,
LayerList
) {
//Create a map based on an ArcGIS Online web map id
arcgisUtils.createMap("f63fed3f87fc488489e27c026fa5d434", "map").then(function(response){
var myWidget = new LayerList({
map: response.map,
layers: arcgisUtils.getLayerList(response)
},"layerList");
myWidget.on("toggle",function(evt){
if(busy) return;
selectedLayerSubIndex = evt.subLayerIndex;
if(selectedLayerSubIndex) return;
selectedLayerIndex = evt.layerIndex;
visibility = evt.visible;
elm = $("#layerListPane input[type=checkbox][data-layer-index="+selectedLayerIndex+"]:not([data-sublayer-index])");
otherCheckedElems = $("#layerListPane input[type=checkbox][data-layer-index!="+selectedLayerIndex+"]:not([data-sublayer-index]):checked");
if(visibility){
busy=true;
otherCheckedElems.each(function () {
$(this).click();
});
busy=false;
}
else{
checkedLength = otherCheckedElems.length
if(checkedLength==0) setTimeout("elm.click();", 100);
}
})
myWidget.startup();
});
});
</script>
</head>
<body class="claro">
<div class="container" data-dojo-type="dijit/layout/BorderContainer"
data-dojo-props="design:'headline',gutters:false">
<div id="layerListPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'right'">
<div id="layerList"></div>
</div>
<div id="map" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"></div>
</div>
</body>
</html>
index.html
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-app="webQueryApp">
<div ng-controller="TestAppController">
<div class="operationalArea" my-Draggable > click me </div>
</div>
</div>
</body>
</html>
-
style.css
.operationalArea {
background-color: #eeeeee;
height: 100px;
width: 100px;
float: left;
padding: 5px;
}
app.js
var webQueryApp = angular.module("webQueryApp", [ ]);
webQueryApp.directive('myDraggable', function(){
return{
//link start
link: function ($scope, element, attrs) {
element.bind('click', function(event) {
console.log("element clicked and arr is "+attrs.arr);
});
}
//link end
};
});
webQueryApp.controller('TestAppController', function($scope, $http) {
var app = this;
console.log("hello console");
$scope.arr=[1,2,3,4];
});
you can see in plunker
http://plnkr.co/edit/aabS53ZgjKnrXWu1aFtt?p=preview
i want to use controller arr value in custom directive.
but it says undefined. while i am tring i can't have the scope of table.
other wise send me a reference where i can found the solution.
From the plunker you provided, just modify the directive scope property to the follwing
scope: {
data: '=',
}
and you are going to be able to use the array by calling $scope.data