How to make a list of modifiable object in Polymer - javascript

Here is the host element.
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/paper-input/paper-input.html">
<link rel="import" href="../common-settings-service/common-settings-service.html">
<link rel="import" href="../bower_components/paper-button/paper-button.html"/>
<link rel="import" href="../bower_components/paper-material/paper-material.html"/>
<link rel="import" href="../bower_components/iron-list/iron-list.html">
<link rel="import" href="../bower_components/iron-flex-layout/iron-flex-layout.html">
<dom-module id="common-settings">
<style>
:host {
display: block;
}
paper-material {
background: #FFFFFF;
}
.container {
#apply(--layout-horizontal);
}
.windowItem {
#apply(--layout-horizontal);
}
.list {
#apply(--layout-flex);
#apply(--layout-vertical);
}
.item {
#apply(--layout-horizontal);
margin: 16px 16px 0 16px;
padding: 20px;
border-radius: 8px;
background-color: white;
border: 1px solid #ddd;
}
</style>
<template>
<common-settings-service
id="commonSettings"
url="/board_service/common_settings/"
settings="{{settings}}"></common-settings-service>
<paper-material elevation="1">
<div>
<h3> Настройки обработки</h3>
<h4>Окна</h4>
<iron-list items="{{settings.timeWindows}}" as="item">
<template>
<div>
<paper-input type="number"
value="{{item}}" label="Размер окна"></paper-input>
<paper-button raised on-tap="removeWindow">Удалить</paper-button>
</div>
</template>
</iron-list>
<!--<template is="dom-repeat" items="{{settings.timeWindows}}">-->
<!--<div class="windowItem">-->
<!--<paper-input type="number"-->
<!--value="{{item}}" label="Размер окна"></paper-input>-->
<!--<paper-button raised on-tap="removeWindow">Удалить</paper-button>-->
<!--</div>-->
<!--</template>-->
<paper-button raised on-tap="addWindow">Добавить</paper-button>
<paper-input type="number"
value="{{settings.signalUpperLimit}}"
label="Верхнее ограничение сигнала"></paper-input>
<paper-input type="number"
value="{{settings.signalLowerLimit}}"
label="Нижнее ограничение сигнала"></paper-input>
<paper-input type="number"
value="{{settings.accumulationTimeSeconds}}"
label="Время накопления в секундах"></paper-input>
<paper-input type="string"
value="{{settings.serverIp}}"
label="IP адрес сервера обработки"></paper-input>
<paper-input type="number"
value="{{settings.thresholdProcessingSettings.windowSize}}"
label="Размер окна для фильтрации порогов"></paper-input>
<paper-input type="number"
value="{{settings.thresholdProcessingSettings.thresholdLowerLimit}}"
label="Нижнее ограничение порогов"></paper-input>
<paper-input type="number"
value="{{settings.thresholdProcessingSettings.thresholdUpperLimit}}"
label="Верхнее ограничение порогов"></paper-input>
<paper-input type="number"
value="{{settings.activeChannelsLimitPercent}}"
label="Ограничение на сработавшие каналы в процентах"></paper-input>
</div>
</paper-material>
</template>
</dom-module>
<script>
Polymer({
is: 'common-settings',
removeWindow: function () {
this.$.commonSettings.removeWindow(20);
},
addWindow: function () {
this.$.commonSettings.addWindow(20);
console.log(this.$.commonSettings.settings.timeWindows);
}
});
</script>
And here is child element
<link rel="import" href="../bower_components/polymer/polymer.html">
<script>
Polymer({
is: 'common-settings-service',
behaviors: [MyBehaviors.DefaultServiceBehavior],
properties: {
settings: {
type: Object,
notify: true,
value: {
segments: [
{
first_index: 0,
last_index: 960
}
],
timeWindows: [10],
signalUpperLimit: 100,
signalLowerLimit: -100,
accumulationTimeSeconds: 600.0,
serverIp: "127.0.0.1",
thresholdProcessingSettings: {
windowSize: 10,
thresholdLowerLimit: -100,
thresholdUpperLimit: 100
},
activeChannelsLimitPercent: 10.0
}
}
},
getSettingsFromResponse: function (response) {
return response._embedded.commonSettingses[0];
},
removeWindow: function (size) {
var index = this.settings.timeWindows.indexOf(size);
this.pop('settings.timeWindows', index);
},
addWindow: function(size) {
this.push('settings.timeWindows', size);
}
});
</script>
I can add and remove elements (while I don't know right now how to remove specific element) from array and I can see that it's removed from list also. But when I change value in field this change isn't reflected in bounded list element. How can I change that?

Put set(path, value) in on-change event, e.g.:
<paper-input on-change="update_property"
id="settings.signalUpperLimit"
type="number"
value="{{settings.signalUpperLimit}}"
label="Верхнее ограничение сигнала"></paper-input>
Inside update_property do change the value:
update_property: function(e, detail, sender) {
// from sender: take the new value and it's id.
console.log(sender);
var id = sender.id;
//... take the new value
// locate the property path in the array and change it
//... set(path, value)
}

Related

How to take the value out of a directory that is inside a list?

I'm using JSON, Java and polymer in my code.
When my button is pressed a function will be called and the java backend will send a list of "teachers". It prints it out on my website as the following:
Code :
handleAjaxResponse(result) {
this.$.response_text.textContent = JSON.stringify(result.detail.response.docenten);
Result:
[{"docentnaam":"Alex"},{"docentnaam":"Jos"},{"docentnaam":"Dick"},{"docentnaam":"Annemarije"},{"docentnaam":"Martijn"},{"docentnaam":"John"},{"docentnaam":"Bart"},{"docentnaam":"Bart"},{"docentnaam":"Peter"},{"docentnaam":"Dietske"},{"docentnaam":"Peter"}]
It seems to be a directory inside a list, i don't need all those information. The only thing i need is the values inside the directory.
My code in Java:
public void handle(Conversation conversation) {
JsonObject jsonIn = (JsonObject) conversation.getRequestBodyAsJSON();
String name = jsonIn.getString("user");
JsonObjectBuilder objBuilder = Json.createObjectBuilder();
objBuilder.add("message", "The server says: Hi " + name + "!");
JsonArrayBuilder docentenlijst = Json.createArrayBuilder();
informatieSysteem.getDocenten().forEach(docent -> docentenlijst.add(Json.createObjectBuilder().add("docentnaam", docent.getVoornaam()).build()));
objBuilder.add("docenten", docentenlijst.build());
conversation.sendJSONMessage(objBuilder.build().toString());
}
I tried alot to figure out how to get the values out of it only but nothing helped. I hope someone can help me out. Thank you very much.
Polymer/html:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-radio-button/paper-radio-button.html">
<link rel="import" href="../../bower_components/paper-radio-group/paper-radio-group.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/iron-ajax/iron-ajax.html">
<dom-module id="my-presentie">
<template>
<style>
:host {
display: block;
}
#lijst {
position: fixed;
left: 550px;
top: 300px;
}
#studentenlijst {
position: fixed;
left: 850px;
top: 280px;
}
</style>
<div id="lijst">
<paper-radio-group selected="klas">
<paper-radio-button name="v1b">V1B-ICT</paper-radio-button><br>
<paper-radio-button name="v1c">V1C-ICT</paper-radio-button><br>
<paper-radio-button name="v1d">V1D-ICT</paper-radio-button><br>
<paper-radio-button name="v1e">V1E-ICT</paper-radio-button>
</paper-radio-group>
<paper-button on-click="clickHandler">Volgende</paper-button><br/>
</div>
<div id="studentenlijst">
<paper-input label="Uw naam:" value="{{name}}"></paper-input>
<p>Studenten: <span id="response_text"></span></p>
</div>
<iron-ajax id="studentenlijst_call" method="POST" url="/example" handle-as="json" on-response="handleAjaxResponse"></iron-ajax>
</template>
<script>
/**
* #customElement
* #polymer
*/
class WebappApp extends Polymer.Element {
static get is() { return 'my-presentie'; }
static get properties() {
return {
name: {
type: String,
value: ''
}
};
}
clickHandler() {
this.$.studentenlijst_call.contentType="application/json";
this.$.studentenlijst_call.body = { "user": this.name };
this.$.studentenlijst_call.generateRequest();
}
handleAjaxResponse(result) {
this.$.response_text.textContent = JSON.stringify(result.detail.response.docenten);
}
}
window.customElements.define(WebappApp.is, WebappApp);
</script>
</dom-module>
You may simply use array.map method;
handleAjaxResponse(result) {
var r = result.detail.response.docenten;
this.$.response_text.textContent = r.map(o=> {return o.docentnaam;})
}
<div id="test">Test</div>
<script>
var docents = [{"docentnaam":"Alex"},{"docentnaam":"Jos"},{"docentnaam":"Dick"},{"docentnaam":"Annemarije"},{"docentnaam":"Martijn"},{"docentnaam":"John"},{"docentnaam":"Bart"},{"docentnaam":"Bart"},{"docentnaam":"Peter"},{"docentnaam":"Dietske"},{"docentnaam":"Peter"}]
document.getElementById('test').innerHTML= docents.map(o=> {return o.docentnaam;} );
</script>

Polymer - <iron-ajax> data binding

I have created a polymer element and inside the element I am fetching a small little .json file that I will need to use for various parameters.
My JSON file looks like this.
{
"server_name" : "XMS Development Site",
"server_url" : "test0",
"xms_version" : "3.0.0 BETA",
"rest": {
"os_url" : "test1",
"mbo_url": "test2",
"login_url": "test3",
"logout_url": "test4",
}
}
I am unable to access the values in this JSON object from my iron-ajax request. The {{response.xms_version}}binding just appears blank. The on-response function just displays null. Looking in chrome's dev tools, the JSON file is retrieved and the data is all there. It seems that for some reason I am just unable to bind to it. I am not trying to use the dom-repeat method as I just need to be able to bind to these data points.
My element looks like this:
<link rel="import" href="../../bower_components/polymer/polymer.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/iron-ajax/iron-ajax.html">
<dom-module id="xms-login">
<template>
<style>
:host {
display: block;
}
.login-form-button{
padding: 16px;
text-align: center;
}
.login-form{
}
.login-field{
padding-top: 16px;
padding-left: 16px;
padding-right: 16px;
}
.login-button{
background-color: var(--default-primary-color);
color: var(--text-primary-color);
}
.xms-logo-svg{
text-align: center;
padding-top: 64px;
}
.version-number-text{
text-align: center;
postion: absolute;
bottom: 0;
}
</style>
<iron-ajax id="testAjax" auto
url="../../xms.json"
handle-as="json"
method="GET"
on-response="handleResponse"
last-response="{{response}}"></iron-ajax>
<xms-auth id="xmsAuthHandler" authheader="{{computeEncodedLogin(username, password)}}" provider="rest"></xms-auth>
<div class="login-form">
<div class="login-form-fields">
<paper-input class="login-field" type="text" label="Username" value="{{username}}"></paper-input>
<paper-input class="login-field" type="password" label="Password" value="{{password}}"></paper-input>
</div>
<div class="login-form-button">
<paper-button raised class="login-button" onclick="xmsAuthHandler.login()">Login</paper-button>
</div>
<div class="version-number-text">{{response.xms_version}}</div>
</div>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'xms-login',
properties: {
user: {
type: String,
notify: true
},
username: {
type: String,
notify: true
},
password: {
type: String,
notify: true
},
},
computeEncodedLogin: function( username, password ){
return btoa(username + ':' + password);
},
handleResponse: function(request){
var myResponse = request.detail.response;
console.log(myResponse);
}
});
})();
</script>
</dom-module>
Issue is fixed, was caused by incorrect JSON data.

Polymer local dom

I played around with Polymer's local dom selector $$. I want to know if an element with a certain attribute exists. I wrote below example.
Is it by intention, that I cannot reach elements within other custom elements with the $$ selector?
How can I check for the existence of elements inside anothers element?
Is it good to go with document.querySelector?
<script src="https://elements.polymer-project.org/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.0.1/lib/polymer/polymer.html">
<dom-module id="my-moduleone">
<style>
:host {
height: 100%;
width: 100%;
display: block;
}
</style>
<template>
<div class="content-wrapper">
<content select="*" />
</div>
Counter 1: <span counter1>0</span>
<input type="button" value="Increment counter" on-click="_incrementCounter"/>
</template>
<script>
(function () {
Polymer({
is: 'my-moduleone',
_incrementCounter: function() {
this.$$('[counter1]').innerHTML++;
this.querySelector('[counter2]').innerHTML++;
this.$$('[counter3]').innerHTML++;
}
});
})();
</script>
</dom-module>
<dom-module id="my-moduletwo">
<style>
:host {
width: 100%;
display: inline-block;
}
.counter {
float: left;
height: 100px;
width: 100px;
display: block;
}
.blue {
background-color: lightblue;
}
.magenta {
background-color: magenta;
}
</style>
<template>
<content select="*" />
<span class="counter blue">
Counter 2: <span counter2>0</span>
</span>
<span class="counter magenta">
Counter 3: <span counter3>0</span>
</span>
</template>
<script>
(function () {
Polymer({
is: 'my-moduletwo'
});
})();
</script>
</dom-module>
<my-moduleone>
<my-moduletwo>
</my-moduletwo>
</my-moduleone>
You've said it yourself: this.$$ is a local dom selector. That means you cannot access elements that are added in the light dom. If you are going to access elements in the light dom (or access elements that aren't added in the local dom at registration time), use Polymer.dom instead. This is Polymer's suggested way of manipulating elements, be it in the light dom or the local dom. You also should not use document.querySelector in accessing elements that are inside the local dom of the element since this method cannot (by default) access the shadow dom.
Here is an example of using Polymer.dom:
<!doctype html>
<html>
<head>
<base href="http://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
</head>
<body>
<dom-module id="my-component-one">
<template>
<div class="content-wrapper">
<content select="*" />
</div>
Counter 1: <span counter1>0</span>
<input type="button" value="Increment counter" on-click="_incrementCounter" />
</template>
</dom-module>
<dom-module id="my-component-two">
<template>
<content select="*" />
<span class="counter blue">
Counter 2: <span counter2>0</span>
</span>
<span class="counter magenta">
Counter 3: <span counter3>0</span>
</span>
</template>
</dom-module>
<my-component-one>
<my-component-two></my-component-two>
</my-component-one>
<script>
(function() {
Polymer({
is: 'my-component-one',
_incrementCounter: function() {
// Note: Polymer.dom(this) accesses the light dom. Use Polymer.dom(this.root)
// to access the element's local dom
var componentTwo = Polymer.dom(this).querySelector('my-component-two');
if (!componentTwo) return; // don't do anything when there is no my-component-two
// access element's local dom by getting it's root property
var c2_counter2 = Polymer.dom(componentTwo.root).querySelector('[counter2]');
var c2_counter3 = Polymer.dom(componentTwo.root).querySelector('[counter3]');
var c1_counter1 = Polymer.dom(this.root).querySelector('[counter1]'); // this can be shortened to this.$$
var c1c1 = parseInt(c1_counter1.innerHTML);
var c2c2 = parseInt(c2_counter2.innerHTML);
var c2c3 = parseInt(c2_counter3.innerHTML);
c1_counter1.innerHTML = c1c1 + 1;
c2_counter2.innerHTML = c2c2 + 1;
c2_counter3.innerHTML = c2c3 + 1;
}
});
Polymer({
is: 'my-component-two'
});
})();
</script>
</body>
</html>

Polymer add Html tags with properties

My Polymer element displays some properties it gets passed as attributes. The content property may contain some html tags like <br> or <p>. The problem I'm facing with, is, that Polymer doesn't add the tags to the DOM tree, instead it prints them like normal text. Is there a way to force "DOM tree adding"?
The whole element:
<link rel="import" href="paper-toolbar/paper-toolbar.html">
<link rel="import" href="iron-collapse/iron-collapse.html">
<link rel="import" href="paper-material/paper-material.html">
<dom-module id="card-element" is="auto-binding">
<style>
#contentWrapper {
padding: 10px 15px;
}
#toolbar {
--paper-toolbar-background: #607D8B;
--paper-toolbar: {
font-size: 125%;
opacity: 0.9;
};
}
.maxWidth {
width: 100%;
}
</style>
<template>
<paper-material elevation="2" class="maxWidth" id="card" animatedShadow="1">
<paper-material elevation="1" class="maxWidth">
<paper-toolbar on-click="toggleCollapse" id="toolbar" justify="justified">
<span class="title">{{convertedDate}}</span><span class="title">{{fach}}</span>
</paper-toolbar>
</paper-material>
<iron-collapse id="collapse">
<div id="contentWrapper">
<span>{{content}}</span>
</div>
</iron-collapse>
</paper-material>
</template>
<script>
Polymer({
is: "card-element",
properties: {
opened: {
type: Boolean,
value: false
},
fach: {
type: String,
value: "u-oh an Error"
},
content: {
type: String,
value: "u-oh an Error"
}
},
toggleCollapse: function() {
if(this.opened) {
this.$.collapse.hide();
this.$.card.elevation = "2";
this.opened = false;
}
else {
this.$.collapse.show();
this.$.card.elevation = "5";
this.opened = true;
}
},
ready: function() {
var date = new Date(this.datum);
this.convertedDate = date.getDate() + "." + (date.getMonth() + 1) + "." + date.getFullYear();
}
});
</script>
</dom-module>
Polymer not allowed html to prevent XSS attack
But you can do this
<dom-module id="html-echo">
<style>
:host {
display: block;
}
</style>
<template>
</template>
</dom-module>
<script>
(function () {
Polymer({
is: 'html-echo',
properties: {
html: {
type: String,
observer: '_htmlChanged'
}
},
_htmlChanged: function (neo) {
// WARNING: potential XSS vulnerability if `html` comes from an untrusted source
this.innerHTML = neo;
}
});
})();
</script>
Use like
<html-echo html="[[htmlText]]"></html-echo>

Declaring events in polymer

I have the following element declared in polymer
<polymer-element name="Map-List-Element" attributes="mapName recordId">
<template>
<style>
:host {
display: block;
position: relative;
background-color:#fff;
padding: 20px;
font-family: 'Roboto';
font-size:14px;
font-weight:400;
margin-bottom:10px;
border: 1px solid #ddd;
}
core-label {
margin-bottom:20px;
display:block;
}
core-icon {
color:#A0A0A0;
margin-right:10px;
cursor:pointer;
}
</style>
<core-label>{{mapName}}</core-label>
<span flex></span>
<core-icon-button icon="av:play-arrow"></core-icon-button>
<core-icon icon="settings" on-tap="{{settingsClicked}}"></core-icon>
<core-icon icon="delete"></core-icon>
<content/>
</template>
<script>
Polymer({
mapName: "",
recordId: 0,
settingsClicked: function (event, detail, sender) {
this.fire('show-Settings', { recordId: this.recordId, mapName: this.name });
}
});
</script>
</polymer-element>
That in turn is called by the following custom element
<link rel="import" href="elements.html" />
<link rel="import" href="Map-List-Element.html" />
<polymer-element name="Map-List">
<template>
<template repeat="{{m in response.data}}">
<map-list-element mapname="{{m.mapName}}" recordid="{{m.Id}}" on-show-settings="{{showSettings}}">
</map-list-element>
</template>
<core-ajax id="ajax"
auto=true
method="POST"
url="/RoutingMapHandler.php?Command=retrieve&Id=all"
response="{{response}}"
handleas="json"
on-core-error="{{handleError}}"
on-core-response="{{handleResponse}}">
</core-ajax>
</template>
<script>
Polymer('Map-List', {
created: function () {
},
handleError: function (event, detail, sender) {
},
handleResponse: function (event,detail,sender) {
},
showSettings: function (event, detail, sender) {
alert('Fired showSettings');
}
});
</script>
</polymer-element>
When I click on the core-icon with the settings icon it calls the 'settingsClicked' function. The 'event handler' in the Map-List element which contains another alert is not called - the alert in 'showSettings' is not shown.
So given the events declared in the Map-Element element, how do you create the event handler in the Map-List?
Your event handler declaration is correct (on-show-settings="{{showSettings}}" and the corresponding function).
But you got a typo in the fire statement .The event name must be all lowercase. So replace this.fire('show-Settings' with this.fire('show-settings' and your code will work.

Categories