Observing change of a property made within a "brother" polymer element - javascript

I have a parent element with 2 child's:
<dom-module id="app-frontend">
<app-frontend-header logoff="{{_logoff}}" current-page="[[_page]]"></app-frontend-header>
<app-frontend-page-profile id="profilepage"
logoff="{{_logoff}}" name="profile">
</app-frontend-page-profile>
Polymer({
is: 'app-frontend',
properties: {
_logoff: {
type: Boolean,
value: false,
notify:true,
},
});
</dom-module>
I'm changing the value of logoff (from false to true) inside header element and I'm trying to run a function in profile element by using an observer
triggerLogoff: function(logoff) {
debugger;
console.log("header " + logoff);
},
observers: [
'triggerLogoff(logoff)'
]
It doesn't want to run (except at the beginning). I can see the property change is observed in the parent element using a similar observer:
triggerLogoff: function(_logoff) {
if (_logoff==true) {
console.log("changed ");
}
},
observers: [
'triggerLogoff(_logoff)'
]
What am I missing?

Related

JointJs initializing custom element

I have the following custom element:
var ir = joint.dia.Element.define('my.Rectangle', {
attrs: {
body: {
// ...
},
header: {
// ...
}
}
}, {
initialize: function() {
this.on("change:header", function() {
console.log('header change')
}, this), joint.dia.Element.prototype.initialize.apply(this, arguments)
},
markup: [{
tagName: 'rect',
selector: 'body',
}, {
tagName: 'text',
selector: 'header'
}]
});
I want to break the header's text with joint.util.breakText and set the body's size, to fit in it, every time it changes. (Even first time it set)
After
var rect = new joint.shapes.my.Rectangle()
rect.attr('header/text', 'FooBarBaz')
rect.addTo(graph);
nothing happens, the shape is added to the screen, but nothing in the console log.
change:header will listen to changes in the header property. To listen to this, use rect.prop instead of rect.attr:
rect.prop('header', 'FooBarBaz')
From the docs, at http://resources.jointjs.com/docs/jointjs/v2.2/joint.html#dia.Element.prototype.prop:
This is an equivalent of the attr() method but this time for custom data properties.
To listen to attribute changes, use change:attrs:
this.on('change:header', function (element, opt) {
if (opt.propertyPath === 'attrs/header/text') {
console.log('header change');
}
}, this), joint.dia.Element.prototype.initialize.apply(this, arguments);

How to attach nuxeo-tree component to Polymer v1 app

I want to add the <nuxeo-tree> component to my Polymer v1 app, but I'm seeing an error in the console. This is the code I've tried:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/nuxeo-ui-elements/nuxeo-tree/nuxeo-tree.html">
<link rel="import" href="./myVerySpecialLib-import.html">
<dom-module id="my-app">
<template>
tree:<br/>
<nuxeo-tree data="[ title: 'root', children: [ { title: 'a', children: [] }, { title: 'b', children: [ {title: 'x'}, {title: 'y'} ] } ]]]" controller="[[controller]">
<template>
<template is="dom-if" if="[[!opened]]">
<iron-icon icon="hardware:keyboard-arrow-right" toggle></iron-icon>
</template>
<template is="dom-if" if="[[opened]]">
<iron-icon icon="hardware:keyboard-arrow-down" toggle></iron-icon>
</template>
<span select>My title is: [[item.title]]</span>
<span>Am I a leaf? [[isLeaf]]</span>
</template>
</nuxeo-tree>
</template>
<script>
Polymer({
is: 'my-app',
properties: {
data: {
type: String,
value: "[ title: 'root', children: [{ title: 'a',children: []},{title: 'b',children: [{title: 'x'},{title: 'y'}]}]]",
},
opened: {
type: Boolean,
value: true,
},
},
controller: {
// How to get children of a node. Returns a promise.
getChildren: function(node) {
return Promise.resolve(node.children);
},
// Logics you may want to have to control if a node is a leaf.
isLeaf: function(node) {
return node.children.length === 0;
}
},
});
</script>
</dom-module>
And the myVerySpecialLib-import.html file:
controller = {
// How to get children of a node. Returns a promise.
getChildren: function(node) {
return Promise.resolve(node.children);
},
// Logics you may want to have to control if a node is a leaf.
isLeaf: function(node) {
return node.children.length === 0;
}
};
This is the console error:
TypeError: this.controller.isLeaf is not a function
I tried to add the JSON data as a property and also directly into the data field, but neither had a positive effect. How do I fix this?
The myVerySpecialLib-import.html seems to contain a global variable declaration, but that doesn't really help you because <nuxeo-tree> expects controller on the container element (not in a global variable).
Also, your data binding for <nuxeo-tree>.controller is malformed (it's missing a ] at the end):
<nuxeo-tree controller="[[controller]">
And controller probably should be declared as a property if you're binding it. It's currently declared outside the properties object.
// DON'T DO THIS
/*
properties: {...},
controller: {...}
*/
// DO THIS
properties: {
controller: {...}
}
I recommend setting this.controller in the ready() callback of the parent element of <nuxeo-tree> (where this is the container). You could also set <nuxeo-tree>.data via a binding to simplify your HTML template, and that property could be initialized in ready() as well.
ready: function() {
this.data = /* insert data object here */;
this.controller = /* insert controller object here */;
}
demo

Polymer dom-repeat sub property changes child to host wiring

I have a host element binding array of object to child element which has a paper-input to edit its properties. I don't see the value change on input reflected in the host div element. Even though on debug I can see that the host object has the latest edited name. What should I do to get this automatically wired ?
<!-- Host element -->
<dom-module id="host-item">
<template>
<div>
<div>[[selectedEmployee.name]]</div>
<template is="dom-repeat" items="[[employees]]" as="employee">
<item-edit item="[[employee]]"></item-edit>
</template>
</div>
</template>
<script>
Polymer({
is: 'host-item',
properties: {
selectedEmployee: {
type: Object
},
employees: {
type: Array,
value = [ { name: 'Name 1'}, { name: 'Name 2'}, { name: 'Name 2'}]
}
},
ready: function() {
this.selectedEmployee = this.employees[0];
}
});
</script>
</dom-module>
<!-- Child element -->
<dom-module id="item-edit">
<template>
<paper-input id="input" value="{{item.name}}" error-message="Invalid name!"></paper-input>
</template>
<script>
Polymer({
is: 'item-edit',
properties: {
item: {
type: Object
}
}
});
</script>
</dom-module>
Use {{employee}} for 2 way binding. [[...]] is for one way only.
Use notify: true on property definition.
Child element should be defined before the parent.
Here is the working example Plunk, and similar Plunk
<item-edit item="{{employee}}"></item-edit>
...
employee: {
type: Object,
notify: true,
value: function () { return {name: 'Test' }; }
}
Update:
Now "employees" data is in form of an array of objects.
Check out this question for working with arrays:
Polymer, issue with binding array to paper slider value
Plunk
Docs: Binding to array items

How to Troubleshooting Binding

I found a cool project (RoboJS), and I forked it: Forked Repo. My plan was to try to add a nice front end with Polymer 1.0 and learn a little in the process.
What I am having trouble with is getting the binding to show in my component. I've built a really simple "robot" component to show the status of the robot during the game.
To start, all I want to do is to show the name in the title, but it comes out blank. Here's the component:
<dom-module id="robojs-robot-status">
<template>
<div>Robot Name <span>[[robot]]</span><span>{{test}}</span></div>
</template>
</dom-module>
<script>
Polymer({
is: "robojs-robot-status",
properties: {
robot: {
type: String,
value: "testing"
},
test: {
type: String,
value: "testing2"
}
},
ready: function() {
},
init: function() {
console.log(this.robot);
console.log(this.test);
}
});
</script>
On the parent component, I set the robot attribute:
Here's the attribute:
<link rel="import" href="robojs-robot-status.html">
<robojs-robot-status robot="{{robot}}"></robojs-robot-status>
And, I have a script that, for now, sets the value on the ready event:
Polymer({
is: "robojs-arena",
properties: {
robot: {
type: String,
value: "hello"
}
},
ready: function() {
this.games = window.roboJS.games;
console.log(this.games);
//this.robot = {name: "hello"};
this.robot = "hello";
},
init: function() {
console.log("******* init *******");
console.log(this.robot);
document.querySelector("robojs-robot-status").init();
},
pause: function() {
window.roboJS.pause();
},
start: function() {
console.log(window.roboJS);
window.roboJS.resume();
}
});
[[robot]] is blank. {{test}} binds to "testing2".
Using {{robot}} or [[robot]] doesn't make a difference. So, that doesn't have an impact.
If I remove, the "robot" attribute in the parent component, the value works. It shows "testing". So, it is binding, but not with the actual value.
Beyond figuring out what I am doing wrong in this instance, is there a good way to troubleshoot? I am having similar issues in other places in the app.
If this were Angular + jQuery, I would do something like this:
$('robotjs-robot-status').scope().$eval("robot")
I could type that into the developer console in Chrome and see what it said and troubleshoot. I could also use the Batarang extension in Chrome.
With Polymer, I am not sure where to start. Any help/ideas?
If the parent snippet is posted here exactly as it appears in the code, then it's probably to blame. The
<link rel="import" href="robojs-robot-status.html">
should be outside , like
<dom-module id="robojs-robot">
<link rel="import" href="robojs-robot-status.html">
<template>
<robojs-robot-status robotname="{{robotname}}"></robojs-robot-status>
</template>
<script>
Polymer({
is: "robojs-robot",
ready: function() {
console.log('setting to Dilly');
this.robotname = "Dilly";
},
properties: {
robotname: {
type: String,
value: "hello"
}
},
});
</script>
</dom-module>
and then if status is
<dom-module id="robojs-robot-status">
<template>
<div>Robot Name <span>[[robotname]]</span></div>
</template>
<script>
Polymer({
is: "robojs-robot-status",
properties: {
robotname: {
type: String,
value: "testing",
observer: '_robotnameChanged'
}
},
_robotnameChanged: function(newValue, oldValue) {
console.log('_robotnameChanged: newValue='+newValue+' oldValue='+oldValue)
}
});
</script>
</dom-module>
everything works for me.
PS: properties seem to be not really needed here as binding is unidirectional.

Polymer change notification and two-way binding syntax

I'm trying to figure out how to use the 2-way notifications in polymer described here
But while this explains that there is some mechanism for notifying if an object on a child element has changed:
When a sub-property of a property configured with type: Object
changes, an element fires a non-bubbling -changed DOM event
with a detail.path value indicating the path on the object that
changed.
But it doesn't give any clue (that I can sort out) how the syntax would look to script some behaviour based on this change.
For example if I have a parent:
<dom-module id="parent-element">
<template>
<child-element obj="{{myObj}}"></child-element>
</template>
<script>
Polymer({
is: "parent-element",
myObj: {
type: Object
},
parentClick: function(){
this.myName = "Parent";
},
myObjChanged: function(){ //How to handle this event?
console.log("I have no idea what I'm doing")
}
});
</script>
and I have a child element:
<dom-module id="child-element">
<template>
<span on-click="childClick">Click me</span>
</template>
<script>
Polymer({
is: 'child-element',
properties: {
obj: {
type: Object,
notify: true
}
},
ready: function(){
this.obj = {foo: "bar"}
},
childClick: function(){
this.obj.foo = "baz"
}
});
</script>
When the child is clicked, I expect some event to fire and get picked up by the parent, but I have no clue how to script for that event at the parent. What am I missing?
I recently had this problem and did this by firing my own event. You can see the documentation for that here (please note that this documentation is for 0.5 but I have done this with version 1.0). In your child element you could change your childClick function to fire the custom event as follows:
childClick: function(){
this.obj.foo = "baz"
this.fire("child-element-click"); // this can be anything you want...
}
and then in your parent element you want to add a listener to the child-element:
<dom-module id="parent-element">
<template>
<child-element obj="{{myObj}}" on-child-element-click="myObjChanged"></child-element>
</template>
<script>
Polymer({
is: "parent-element",
myObj: {
type: Object
},
parentClick: function () {
this.myName = "Parent";
},
myObjChanged: function () {
console.log("I have no idea what I'm doing")
}
});
</script>

Categories