Is there a way of getting the list of all published properties defined in a polymer component? (e.g. get the available properties of component public API)
<polymer-element name="sample-component"
attributes="foo1 foo2" bar="10">
/* ... */
</polymer-element>
<sample-component foo1="5"></sample-component>
document.querySellector('sample-component').attributes;
// returns bar and foo1 (which have a value assigned to them)
// but I want to get foo1 and foo2
It's best to use element.publish to get the list of published properties for an element. (In polymer 1.0 element.properties does the same).
element.getAttribute('attributes) won't include the publish properties that are setup in a publish block.
You can access the element definition (i.e. the polymer-element itself) through the element property. So
document.querySelector('sample-component')
.element.getAttribute('attributes')
gives you 'foo1 foo2' (btw. inside an element you can simply write this.element.)
Be aware that this only works after Polymer has registered and processed all elements, so depending on where you want to use this statement, you may have to put it into a polymer-ready event handler:
<script>
addEventListener('polymer-ready', function() {
console.log(document.querySelector('sample-component')
.element.getAttribute('attributes'));
});
</script>
Update:
If you want to get a list of all published properties (i.e. the ones in the attributes attribute plus the ones of the publish: {} property), you can use
Object.keys(document.querySelector('sample-component').publish)
which gives you ['foo1', 'foo2'].
Related
I use the Universal style for my QtQuick app and I want to provide a ColorDialog for adjusting the accent color.
I have something like this:
ColorDialog {
id: accChooser
title: "Please choose a color"
onAccepted: {
setGlobalAccentColor(accChooser.color)
}
}
*Note that I cannot simply write Universal.accent=... inside a child item because it has no effect on the parent.See this.
and this function:
function setGlobalAccentColor(accentColor){
Universal.accent = accentColor
}
It works when the function setGlobalAccentColor is defined within the same QML file as accChooser,but if I define that function inside an external JS file (say helpers.js) and import it via:
import "helpers.js" as JSHelpers
and use it this way:
ColorDialog{
...
JSHelpers.setGlobalAccentColor(colorDialog.color)
...
}
it doesn't work.There's no specific error or warning message in the output of the app.
Thanks.
May be it is required to import the universal style in the javascript file.
The documentation universal style says below (look in dependency section)
The Universal style must be separately imported to gain access to the
attributes that are specific to the Universal style
You can try importing as said below into your javascript (helpers.js) file.
.import QtQuick.Controls.Universal 2.12 as JsUniversal
And then try accessing (like example: JsUniversal.accent..).
Note that I cannot simply write Universal.accent=... inside a child item because it has no effect on the parent.See this.
While setting it to the child won't affect your whole application, you can set it directly to the whole window.
Window.window.Universal.accent = accentColor;
Universal is an attached object, you can attach it to an abitrary object, not just the current one, by doing <object>.<AttachingType>.
We attach it to the parent window by accessing the window via another attached property: Window.window.
The web components made with stenciljs don't extend HTMLElement. How can I access the native attributes and use them in my component, say the title attribute? When I add #Prop() title and use it in my template an error is shown.
Adding #Prop() also makes the attributes visible in the generated documentation. How can I add the used or required native attributes to the generated documentation?
Compiler error I'm getting:
The #Prop() name "title" is a reserved public name. Please rename the "title" prop so it does not conflict
with an existing standardized prototype member. Reusing prop names that are already defined on the element's
prototype may cause unexpected runtime errors or user-interface issues on various browsers, so it's best to
avoid them entirely.
Yes, you are not allowed to do so but you can pass HTML attributes directly to the element without declaring them with the #Prop decorator. In your case, just pass title to your component.
<your-component title="test title"></your-component>
Then, if you would like to read the value of your title attribute, you have to get the reference to the host element first.
#Element() host: HTMLElement;
Then, you can read it with your host element's getAttribute method, for instance:
componentDidLoad() {
const title = this.host.getAttribute('title');
console.log(title); // or do something with it
}
#Prop() is like reading from tag to component
#Prop({"reflectToAttr": true}) will keep a two way binding and updates both - tag to component & component to tag
It's important to know that you are not allowed to update your #Prop variables inside the component until you specifically allow it with the mutable property. #Prop({"mutable": true})
If you want both just use comma seperated syntax like:
#Prop({"mutable": true, "reflectToAttr": true})
For details please go here:
https://stenciljs.com/docs/properties
I faced sometimes some issues using the native attributes like "title", "focus" and so on. The correct way would be using "data" before the attribute like "data-title", "data-focus" and in the component #Prop() dataTitle, #Prop() dataFocus.
But to be honest i don't like that the developer using the web-components have to learn a web-component specific syntax so i use the native attributes anyway. Which results sometimes in some errors that you can fix easily. But this would be a topic for another question.
#Update
I just realized that in newer StencilJS versions is just #Prop({"reflect": true}) but the idea is still the same
I'm using Polymer 2.0 and I have a dom-repeat for different to-do cards. What I want to do is remove the card when I click on it.
So I tried this on-tap=deleteNote([[index]]) which uses the index from the dom-repeat. However Polymer doesn't execute the function.
What am I doing wrong?
Another solution could be the dataset object within the event.target. You can define your properties with the data- prefix:
<div on-tap="doSomething" data-item$="[[item]]"></div>
And within your doSomething() listener you can get the dataset object:
doSomething(event) {
const item = event.target.dataset.item;
...
}
You can access the model via the event argument's model property.
So you can access the index from event.model.index.
Well, I am aware you can't. There are many discussions about that on the internet.
Of course, there is a way how to pass argument to function. You can save [[index]] in attribute of element and then get the attribute when needed.
Example:
<div on-tap='_deleteNote' indexed$='[[index]]'>
Then in script:
_deleteNote(e) {
var index = e.target.getAttribute('indexed');
...
}
Once you get index, you can do whatever you want with it.
Don't forget to extend Polymer gestures if you are not using hybrid elements in Polymer 2.0.
class Foo extends Polymer.GestureEventListeners(Polymer.Element) {}
More about it: https://www.polymer-project.org/2.0/docs/devguide/gesture-events#using-gesture-events
What is hybrid element: https://www.polymer-project.org/2.0/docs/devguide/hybrid-elements
on-tap does not appear to be implemented in Polymer 2.0. If you instead use on-click then it will work.
EDIT: see below comment.
I'm generating a JSON with a random set of X's and O's and trying to plot them into a simple grid using a custom element in polymer. When I first open the page everything runs fine and i see a different grid each time. I've also added a button on an index.html page that regenerates the JSON with a new set of X's and O's, but the polymer element wont flag an event change or update its child elements with the new data.
It only seems to be an issue with my JSON object, because if i change it to a string, i get a change notification each time...
i have written a simple "forceDB.js" script that generates the JSON and passes it to the polymer element with .setAttribute('layout', data) how do I notifiy the change to polymer and have all the children elemtents of my polymer script update?
The JSON object looks like this
let data = {
"a1":"",
"a2":"",
"a3":"",
"b1":"",
"b2":"",
"b3":"",
"c1":"",
"c2":"",
"c3":""
};
my polymer script side of the element looks like this...
enter code here
<script>
Polymer({
is:'grid-layout',
properties:{
layout: {
type: Object,
reflectToAttribute : true
},
observers: 'layoutChanged(layout.*)'
},
setLayout: function(newdb){
console.log('new - ' + JSON.stringify(newdb));
this.set('layout', newdb);
},
layoutChanged: function(changedthing){
alert("Layout Changed!");
},
});
</script>
I think that I may be missing a key point in polymer or maybe I'm doing something wrong. But I have a simple X's and O's game that I'm developing to try come to grips with polymers data binding principals and seem to be falling short where.
Could it be that the layout property needs:
notify: true
And it might be helpful to see how you are data binding the layout property to the child elements in the HTML.
I have the following html that is bound to an object containing id and status. I want to translate status values into a specific color (hence the converter function convertStatus). I can see the converter work on the first binding, but if I change status in the binding list I do not see any UI update nor do I see convertStatus being subsequently called. My other issue is trying to bind the id property of the first span does not seem to work as expected (perhaps it is not possible to set this value via binding...)
HTML:
<span data-win-bind="id: id">person</span>
<span data-win-bind="textContent: status converter.convertStatus"></span>
Javascript (I have tried using to modify the status value):
// persons === WinJS.Binding.List
// updateStatus is a function that is called as a result of status changing in the system
function updateStatus(data) {
persons.forEach(function(value, index, array) {
if(value.id === data.id) {
value.status = data.status;
persons.notifyMutated(index);
}
}, this);
}
I have seen notifyMutated(index) work for values that are not using a converter.
Updating with github project
Public repo for sample (not-working) - this is a really basic app that has a listview with a set of default data and a function that is executed when the item is clicked. The function attempts to randomize one of the bound fields of the item and call notifyMutated(...) on the list to trigger a visual updated. Even with defining the WinJS.Binding.List({ binding: true }); I do not see updates unless I force it via notifyReload(), which produces a reload-flicker on the listview element.
To answer your two questions:
1) Why can't I set id through binding?
This is deliberately prevented. The WinJS binding system uses the ID to track the element that it's binding to (to avoid leaking DOM elements through dangling bindings). As such, it has to be able to control the id for bound templates.
2) Why isn't the converter firing more than once?
The Binding.List will tell the listview about changes in the contents of the list (items added, removed, or moved around) but it's the responsibility of the individual items to notify the listview about changes in their contents.
You need to have a data object that's bindable. There are a couple of options:
Call WinJS.Binding.as on the elements as you add them to the collection
Turn on binding mode on the Binding.List
The latter is probably easier. Basically, when you create your Binding.List, do this:
var list = new WinJS.Binding.List({binding: true});
That way the List will call binding.as on everything in the list, and things should start updating.
I've found that if I doing the following, I will see updates to the UI post-binding:
var list = new WinJS.Binding.List({binding: true});
var item = WinJS.Binding.as({
firstName: "Billy",
lastName: "Bob"
});
list.push(item);
Later in the application, you can change some values like so:
item.firstName = "Bobby";
item.lastName = "Joe";
...and you will see the changes in the UI
Here's a link on MSDN for more information:
MSDN - WinJS.Binding.as
Regarding setting the value of id.
I found that I was able to set the value of the name attribute, for a <button>.
I had been trying to set id, but that wouldn't work.
HTH
optimizeBindingReferences property
Determines whether or not binding should automatically set the ID of an element. This property should be set to true in apps that use Windows Library for JavaScript (WinJS) binding.
WinJS.Binding.optimizeBindingReferences = true;
source: http://msdn.microsoft.com/en-us/library/windows/apps/jj215606.aspx