No communication between custom Polymer components - javascript

I've written a single custom Polymer component that has multiple smaller custom components designed to one specific step of an entire process.
The elements are supposed to request specific input parameters and each step builds upon the previous steps. The final component contains the results retrieved from an API that accepts the input gathered from the first steps.
My problem is that I can't get info from one component to the next. I have this issue in practically every component I use, so I suspect the way I want to do it is the problem.
The first problem is that I need to retrieve a list of possibilities from the API, and display this list in a dropdown in multiple child components.
I put this list in a Polymer property, but the auto binding does not fire and the data change is not properly propagated down to the child components (if at all). I define a few iron-ajax elements that fetch the data OK, and have a template with child components that need the output of these iron-ajax elements.
<template>
<iron-ajax auto url="{{typesURL}}" handle-as="json"
on-response="handleTypesResponse"></iron-ajax>
<!-- more iron-ajax elements -->
<section id="activities">
<template is="dom-repeat" items="{{activities}}" as="activity">
<my-activity activity="{{activity}}"
types="{{types}}" />
</template>
</section>
<!-- more classic html elements -->
</template>
My url is straightforward and it casts into an Array just fine, but the template in activities is not reloaded and edited if I add an item to the activity array. How could I accomplish this?
A second issue that I'm facing is getting the 'result' of a component.
I have a form where I want the user to specify times. For this, I'm using paper-time-picker. When choosing a time however, and returning to the underlying web component, the time is not changed.
This is the code that defines the dialog:
<paper-dialog id="timeDialog" modal class="paper-time-picker-dialog" entry-animation="scale-up-animation" exit-animation="fade-out-animation">
<h2>Start time <span>{{activity.name}}</span></h2>
<paper-time-picker id="startTimePicker"></paper-time-picker>
<div class="buttons">
<paper-button dialog-dismiss>Cancel</paper-button>
<paper-button dialog-confirm autofocus on-tap="confirmTime">OK</paper-button>
</div>
</paper-dialog>
And these functions defined below the Polymer properties both show and retrieve the dialog and result:
showAttachedDialog: function (id) {
var button = this.$$(id);
if (!button.hasAttribute('data-dialog')) {
return;
}
var dialogId = '#' + button.getAttribute('data-dialog');
var dialog = this.$$(dialogId);
if (dialog) {
dialog.open();
}
},
confirmTime: function () {
this.activity['time'] = this.$$('#timePicker').time;
this.notifyPath('activity.time', this.activity.time);
console.log(this.activity);
console.log("time activity: " + this.activity.time);
},
The console output turns up empty (as in 'time activity: '). Does anyone see what I'm doing wrong? Do ask for more information if you require any to see what I may be missing here.
Thank you.

regarding activities thingy - you should use Polymer's push, pop etc, see https://www.polymer-project.org/1.0/docs/devguide/templates.html#dom-repeat. Or manualy invoke notifyPath. This works:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>xxz</title>
<script src="./bower_components/webcomponentsjs/webcomponents.js"></script>
<link rel="import" href="./bower_components/polymer/polymer.html">
<link rel="import" href="bower_components/paper-time-picker/paper-time-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/paper-dialog/paper-dialog.html">
<link rel="import" href="bower_components/neon-animation/animations/scale-up-animation.html">
<link rel="import" href="bower_components/neon-animation/animations/fade-out-animation.html">
<dom-module id="my-activity">
<style>
:host{
display: block;
}
</style>
<template>
Activity <span>{{activity.name}}</span>
<paper-button on-click=showAttachedDialog>Time dialog <span>{{activity.time}}</span></paper-button>
<paper-dialog id="timeDialog" modal class="paper-time-picker-dialog" entry-animation="scale-up-animation" exit-animation="fade-out-animation">
<h2>Activity name <span>{{activity.name}}</span></h2>
<!-- from https://github.com/bendavis78/paper-time-picker -->
<paper-time-picker id="startTimePicker"></paper-time-picker>
<!--unfortunately paper-time-picker is not a iron-input (is="iron-input") so you can't jut bind to its value-->
<!--start time: <paper-input id="time" value="{{activity.time}}"></paper-input>-->
<div class="buttons">
<paper-button dialog-dismiss>Cancel</paper-button>
<paper-button dialog-confirm autofocus on-tap="confirmTime">OK</paper-button>
</div>
</paper-dialog>
</template>
<script>
HTMLImports.whenReady(function () {
Polymer({
is: "my-activity",
activity: Object,
listeners: {
'startTimePicker.time-changed': '_onTimeChanged'
},
//this is not needed if time is copied in confirmTime
_onTimeChanged: function(){
if (this.activity) {//first event is fired before activity is set
console.log("time activity: " + this.activity.time+' startTimePicker.time='+ this.$.startTimePicker.time);
this.activity.time = this.$.startTimePicker.time;
}
},
showAttachedDialog: function (event /*id*/) {
// that's I can't comprehend
// var button = this.$$(id);
// if (!button.hasAttribute('data-dialog')) {
// return;
// }
//
// var dialogId = '#' + button.getAttribute('data-dialog');
// var dialog = this.$$(dialogId);
// if (dialog) {
// dialog.open();
// }
this.$.timeDialog.open();
},
confirmTime: function () {
// this.activity['time'] = this.$$('#timePicker').time;
// this.notifyPath('activity.time', this.activity.time);
this.activity.time = this.$.startTimePicker.time;
console.log("time activity: " + this.activity.time+' startTimePicker.time='+ this.$.startTimePicker.time);
}
})
});
</script>
</dom-module>
<dom-module id="my-element">
<template>
<paper-button on-click=handleTypesResponse>Kinda call ajax</paper-button>
<section>
<template is="dom-repeat" items="{{activities}}" as="activity">
<my-activity activity="{{activity}}" />
</template>
</section>
</template>
<script>
HTMLImports.whenReady(function () {
Polymer({
is: "my-element",
handleTypesResponse: function () {
this.splice('activities', 0, 3);
for (var i = 0; i < 10; i++) {
console.log('i=' + i);
this.push('activities', {name: 'name'+i, time: new Date()});
}
},
ready: function() {
this.activities = [];
this.push('activities', {name: 'name XXX', time: new Date()});
this.push('activities', {name: 'name YY', time: new Date()});
this.push('activities', {name: 'name ZZ', time: new Date()});
}
});
});
</script>
</dom-module>
</head>
<body>
<my-element></my-element>
</body>
</html>

Related

Using generated Stripe checkout button

I'm trying to implement in my VueJS Project a checkout button generated from the Stripe Dashboard.
I feel like i'm not doing it the right way, so if you have advises i would like to hear them.
I have add <script src="https://js.stripe.com/v3/"></script> in index.html.
the 1st error i get
the 2nd error i get
Here is my Vue component.
<template>
<div>
<button
style="background-color:#6772E5;color:#FFF;padding:8px 12px;border:0;border-radius:4px;font-size:1em"
id="checkout-button-MY_PLAN"
role="link"
>
Checkout
</button>
<div id="error-message"></div>
</div>
</template>
<script>
(function() {
let stripe = Stripe('MY_KEY');
let checkoutButton = document.getElementById('MY_PLAN');
checkoutButton.addEventListener('click', function () {
stripe.redirectToCheckout({
items: [{plan: 'MY_PLAN', quantity: 1}],
successUrl: '',
cancelUrl: '',
})
.then(function (result) {
if (result.error) {
let displayError = document.getElementById('error-message');
displayError.textContent = result.error.message;
}
});
});
})();
</script>
<style scoped>
</style>
If i can't use Stripe in a VueJS Project how can i get around the problem without modifying all my project ?
For the first error where Stripe is undefined. That is likely because the Stripe.js library isn't loaded before that code runs. You'll need to ensure that you've included Stripe.js [1] with this tag in your HTML before any of your JavaScript using Stripe is executed. Note that it's not loaded async.
<script src="https://js.stripe.com/v3/"></script>
The second error is because when you're attempting to getElementById the ID that you're passing is not the same as the ID in the HTML for the button.
The button's ID is checkout-button-MY_PLAN and the ID you're trying to find the button with by passing is MY_PLAN. I would recommend updating your call to getElementById to:
let checkoutButton = document.getElementById('checkout-button-MY_PLAN');
[1] https://stripe.com/docs/js/including

SAPUI5 Select first item in list after rendering

I have a Master-Detail application and I would like the first list item to be selected automatically once the application is loaded. I have tried the following solution but it does not work:
onAfterRendering: function() {
var oList = this.getView().byId("bankList");
var aItems = oList.getItems("listItems");
console.log(aItems);
if (aItems.length) {
aItems[0].setSelected(true);
}
}
The strange thing is that aItems seems to be empty even though it contains the correct details. Below is what is printed in the console when I console.log(aItems):
The result of console.log(aItems)
Guessing that you are using a sap.m.List, You should use the setSelectedItem() function, that receives the Item object as parameter.
Furthermore I recommend you to avoid using the onAfterRendering lifecycle method, to keep the lifecycle clean. There are usually many items that you can use, for example updateFinished for sap.m.List
Here the snippet
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta charset="utf-8">
<title>MVC with XmlView</title>
<!-- Load UI5, select "blue crystal" theme and the "sap.m" control library -->
<script id='sap-ui-bootstrap' src='https://sapui5.hana.ondemand.com/resources/sap-ui-core.js' data-sap-ui-theme='sap_belize_plus' data-sap-ui-libs='sap.m' data-sap-ui-xx-bindingSyntax='complex'></script>
<!-- DEFINE RE-USE COMPONENTS - NORMALLY DONE IN SEPARATE FILES -->
<!-- define a new (simple) View type as an XmlView
- using data binding for the Button text
- binding a controller method to the Button's "press" event
- also mixing in some plain HTML
note: typically this would be a standalone file -->
<script id="view1" type="sapui5/xmlview">
<mvc:View xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" controllerName="my.own.controller">
<List items="{/options}" mode="SingleSelect" updateFinished="onUpdateFinished">
<StandardListItem title="{value}"></StandardListItem>
</List>
</mvc:View>
</script>
<script>
// define a new (simple) Controller type
sap.ui.controller("my.own.controller", {
onUpdateFinished: function(oEvent) {
var oList = oEvent.getSource();
var aItems = oList.getItems();
oList.setSelectedItem(aItems[0])
}
});
/*** THIS IS THE "APPLICATION" CODE ***/
// create some dummy JSON data
var data = {
options: [{
key: '1',
value: 'option 1'
}, {
key: '2',
value: 'option 2'
}, {
key: '3',
value: 'option 3'
}]
};
var oJSONModel = new sap.ui.model.json.JSONModel();
oJSONModel.setData(data);
// instantiate the View
var myView = sap.ui.xmlview({
viewContent: jQuery('#view1').html()
}); // accessing the HTML inside the script tag above
myView.setModel(oJSONModel);
// put the View onto the screen
myView.placeAt('content');
</script>
</head>
<body id='content' class='sapUiBody'>
</body>
</html>

How to mutate Polymer v1.x property inside ajax request

I+m trying to populate an array based in thr results that I fetch from an Ajax request via iron-ajax
When I try to Access to my property, my watch window displays "not available"
Below is an little example I recreated for explain my issue:
my-component.html
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="../../bower_components/app-storage/app-localstorage/app-localstorage-document.html">
<link rel="import" href="../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
<dom-module id="my-component">
<template>
<div>
<paper-dropdown-menu
id="location" label="Ubicación"
value="{{vehicle.location}}">
</paper-dropdown-menu>
<paper-dropdown-menu id="city" label="Ciudad">
<paper-menu
class="dropdown-content"
selected="{{city.city_code}}"
attr-for-selected="value"
on-iron-select="estadoSeleccionado">
<template id="" is="dom-repeat" items="[[opcionesDisponibilidad]]" as="i">
<paper-item value="[[i.valor]]">[[i.texto]]</paper-item>
</template>
</paper-menu>
</paper-dropdown-menu>
</div>
<iron-ajax
id="ajax"
method="GET"
url="http://localhost:8080/ws.asmx"
params=""
content-type="application/x-www-form-urlencoded; charset=UTF-8"
handle-as="text"
on-response="handlecities"
debounce-duration="300">
</iron-ajax>
<app-localstorage-document id="localStorageElement" key="myapp.login_data" data="{{loginInfo}}"></app-localstorage-document>
</template>
<script>
Polymer({
is: "my-component",
properties:{
vehicle: {
type: Object,
value:{
id: "",
plate: "",
location: ""
}
},
cities:{
notify: true,
type: Array,
value: [{city_code:'0', city_name:'-'}]
}
},
ready:function () {
this.querycities();
},
querycities: function () {
if (this.$.localStorageElement.storage['myapp.login_data']){
this.$.loginInfo = JSON.parse(this.$.localStorageElement.storage['myapp.login_data']);
} else return false;
this.$.ajax.url = this.$.ajax.url + "/listadoCiudades";
this.$.ajax.verbose = true;
this.$.ajax._boundHandleResponse = this.handlecities;
this.$.ajax.params = {dispositivo:'12345', credencial: this.$.loginInfo.cred};
this.$.ajax.generateRequest();
},
handlecities: function (request) {
console.log(request.response);
var xPath = new SoftXpath();
xPath.registerNamespace("","");
xPath.loadXML(request.response);
var cities = xPath.selectNodes("//Ciudad//*[self::Codigo|self::Nombre]");
var xPathElement = new SoftXpath();
if (cities){
for(var i = 1; i < cities.length;i++){
var c = new Object();
c.Codigo = cities[i-1].text;
c.Nombre = cities[i].text;
this.$.cities.push(c);// <---- Here I have not access to my polymer property ' cities '.
//How to update my polymer var cities ??
//Tried also with:
// this.cities --> undefined
// this.$$('#myassignedId').cities --> undefined
}
}
}
})
</script>
</dom-module>
How can I populate my 'cities' property if appears out of scope ?
Well,
After too many try-error variations, finally I found the cause of error.
Line 65:
this.$.ajax._boundHandleResponse = this.handlecities;
Removed that line and all my polymer attributes returned to normality.
I was using that sentence because I was trying to reuse the component for several ajax requests. 'handlecities' is specified as attribute as well, so is redundant (only when there are no intentions of reuse). I still don´t know how to reuse the component defining a custom handler, but for some reason if i use the above sentence, all polymer properties are lost.
So, in the meantime I´m defining several ajax components one for each ajax request

[dom-bind::_createEventHandler]: listener method not defined

I am trying out polymer, but am having a problem in registering methods and calling them, I tried everything on the internet and nothing seems to work, I spent too many hours on this but with no results, please help me
here is my code:
<dom-module id="products-list">
<template>
<template is="dom-bind">
<iron-ajax id="ajax" auto
handle-as="json"
last-response="{{ajaxResponse}}"></iron-ajax>
<div class="main">
<template is="dom-repeat" items="[[ajaxResponse.dataResult]]">
<paper-card heading="[[item.name]]" image="[[item.image]]" class="pb16 w100 flex layout horizontal">
<div class="card-content">[[item.desc]]</div>
<div class="card-actions">
<paper-item>
<strong>[[item.price]]</strong>
<div class="flex"></div>
<paper-button on-click="_addToCart" raised><iron-icon icon="icons:add-shopping-cart"></iron-icon>Add to cart</paper-button>
</paper-item>
</div>
</paper-card>
</template>
</div>
</template>
</template>
<script>
Polymer({
is: "products-list",
ready: function() {
var baseUrl = getBaseURL();
var token = getAccessToken();
var namespace = getNamespace();
var appKey = getAppKey();
var appSecret = getAppSecret();
var url = baseUrl + '/stream/product.json';
var params = {
'page' : 0,
'size' : 25
};
var headers = {
'X-Auth-Token' : token,
'X-NAME-SPACE' : namespace,
'X-APP-KEY' : appKey,
'X-APP-SECRET' : appSecret,
};
var ajax = document.querySelector("#ajax");
ajax.url = url;
ajax.headers = headers;
},
properties: {
},
_addToCart: function (e) {
console.log('You pressed button ' + e.model.item.name);
}
});
</script>
Everything works fine except for clicking the button, I am getting the following error:
[dom-bind::_createEventHandler]: listener method `_addToCart` not defined
Removing the wrapping dom-bind everything will work fine.
<template is="dom-bind">...</template>
dom-bind is not needed in element definitions. It is intended to be used in normal HTML pages, and it starts a new "bind context" for your elements. This is why it doesn't find the method, because it's trying to find the event handler method outside the element definition.
I think you've already solved your problem, so for the others you just replace on-click by on-tap event like this:
<paper-button on-tap="_addToCart">...</paper-button>
<paper-button id="addToCart" raised>
<iron-icon icon="icons:add-shopping-cart"></iron-icon>
Add to cart
</paper-button>
and on ready:
this.$.addtoCart.addEventListener('click',this._addToCart.bind(this))

How to avoid Polymer element's AttributeChanged event calling Multiple times

Actually I am using Polymer elements A ,B , C and D in my Application. Consider the below scenario.
1) Element A has boolean attribute named 'devEnable'
2) Element A has attributeChanged event named 'devEnableChanged'
3) And my business logic is implemented in 'devEnableChanged' event
4) Other elements --> B extends A , C extends A , D extends A
Now I run my application, when the attribute devEnable is changed to true or false then devEnableChanged event is getting fired 3 times because of this my business logic also is getting fired 3 times. So I want to avoid firing devEnableChanged event multiple times.
Is there any way to avoid calling it multiple times ?
Using a base polymer element(A) as kind of composition within a template tag of a former derived polymer element(B, C or D) is an option instead of heritage:
index.html:
<!DOCTYPE html>
<html>
<head>
<script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>
<link rel="import" href="derived-element.html">
</head>
<body>
<derived-element id="derivedElement" value="3546"></derived-element>
<input type="button" id="assignBaseElementButton" value="assign base"/>
<input type="button" id="assignDerivedElementButton" value="assign derived"/>
<input type="text" id="valueField"/>
</body>
<script>
document.getElementById('assignDerivedElementButton').addEventListener('click',function(){
var derivedElement = document.querySelector('#derivedElement');
var textFieldValue = document.getElementById('valueField').value;
// get derived element's attribute value to assign it to a value of valueField textfield
derivedElement.value = textFieldValue;
});
document.getElementById('assignBaseElementButton').addEventListener('click',function(){
var derivedElement = document.querySelector('#derivedElement');
var textFieldValue = document.getElementById('valueField').value;
// get base element's attribute value to assign it to a value of valueField textfield
derivedElement.getBaseElement().value = textFieldValue;
});
</script>
</html>
derived-element.html:
<link rel="import" href="/bower_components/polymer/polymer.html">
<link rel="import" href="/base-element.html">
<polymer-element name="derived-element" attributes="value">
<template>
<!-- embed base element here -->
<base-element id="baseElement"></base-element>
<div>
derived element'value: {{value}}
</div>
</template>
<script>
Polymer('derived-element',{
value: null,
ready:function(){
this.getBaseElement().baseValue = this.value;
},
// watcher for value property
valueChanged: function(oldvalue, newvalue) {
// this method is called once
console.log('my-element', 'oldvalue: ',oldvalue, ' newvalue: ',newvalue);
},
getBaseElement:function(){
return this.$.baseElement;
}
});
</script>
</polymer-element>
base-element:
<link rel="import" href="/bower_components/polymer/polymer.html">
<polymer-element name="base-element">
<template>
<span>Hello from <b>base-element</b>. This is my Shadow DOM. And my value is {{value}}</span>
</template>
<script>
Polymer('base-element',{
value: null,
// watcher for value property
valueChanged: function(oldvalue, newvalue) {
// this method is called once
console.log('base-element', 'oldvalue: ',oldvalue, ' newvalue: ',newvalue);
}
});
</script>
</polymer-element>

Categories