Polymer Properties order ... matters? - polymer-1.0

I am finding very odd behavior of a Polymer element when defining properties of that element... specifically Arrays and Objects.
I have a dom-repeat template displaying this data Array, to give some context.
For example:
//.... Template definition
<script>
Polymer({
is: 'sample-element',
properties:{
user: {
type:Object,
notify: true,
},
data:{
type: Array,
value: function(){
return [
{'name':"Facebook", 'website': "http://www.facebook.com"},
{'name':"Twitter", 'website':"http://www.twitter.com"},
{'name':"Google",'website':"http://www.google.com"}];
},
}
}
});
</script>
This renders incorrectly, however if i switch the order of these properties, data is defined as an Array with 3 Objects when the template renders.
For example:
//.... Template definition
<script>
Polymer({
is: 'sample-element',
properties:{
data:{
type: Array,
value: function(){
return [
{'name':"Facebook", 'website': "http://www.facebook.com"},
{'name':"Twitter", 'website':"http://www.twitter.com"},
{'name':"Google",'website':"http://www.google.com"}];
},
},
user: {
type: Object,
notify: true,
},
}
});
</script>
Any clue why this works for defining the Object last?
Console shows no errors in sample-element either...

If you are using default values the order indeed matters.
Maybe user tries to access the value of data which is not set yet.

Related

Polymer 1.0: How can I add paper-card heading content dynamically

Is there a way I can create paper-card heading dynamically using some property inside custom element? Following is what I tried but didn't work. Probably this is not the way to achieve what I want:( I googled for a couple of hours but ended up with nothing!
Custom Element
<script>
(function () {
'use strict';
Polymer({
is: 'nearest-customers',
properties: {
customers: {
type: Array,
value: [],
notify: true
},
cardViewMaxRecords: {
type: Number,
notify: true
},
showFullCustomerList: {
type: Boolean,
value: false,
notify: true
},
headingContent: {
type: String,
value: 'Custom card heading'
}
},
ready: function () {
this.heading.textContent = this.headingContent
},
});
})();
</script>
HTML
<nearest-customers id="nearestCustomers" card-view-max-records="3"></nearest-customers>
...
...
...
<script type="text/javascript">
window.addEventListener('WebComponentsReady', function (e) {
var nearestCustomers = document.querySelector("#nearestCustomers");
nearestCustomers.headingContent= "<a href='someurl'><iron-icon icon='fa:arrow-left'></iron-icon></a> This is a new content";
}
</script>
My objective is to put an iron-icon before the heading text and the icon can be used as a link to somewhere.
Thanks in advance
I'm sure there's a better way, but I just added the styles and structure:
<div class="header paper-card">
<div class="title-text paper-card">
<iron-icon icon="book"></iron-icon> Reading List
</div>
</div>

Polymer 1.0: Refresh/Re-Render Computed Value Without Property Binding

I'm trying to re-compute and render a value within a Polymer 1.0 template. However, I'm trying to do this without binding to any properties.
In case it matters, the use case is for a translation mechanism that uses a string key to find the translated value. When the 'translations' value changes, the translate() call needs to be re-computed.
The component definition is as follows :
<dom-module id="my-component">
<template>
<style></style>
<p><span>[[translate("SOME_STRING")]]</span></p>
</template>
<script>
var MyComponent = Polymer({
is: "my-component",
properties: {
translations: {
type: Object,
notify: true,
value: {
"SOME_STRING": "Some String"
}
}
},
translate: function (key) {
if (this.translations.hasOwnProperty(key)) {
return this.translations[key];
}
}
});
</script>
</dom-module>
I can get the refresh to work by adding the translations property to the translate() call as follows :
<p><span>[[translate("SOME_STRING", translations)]]</span></p>
However, what I would like to do is re-compute/refresh without having to put the translations property as a second parameter in every call (there's other reasons too).
Basically, when the translations object updates with different locale translations, I'd like the translate("SOME_STRING") to be re-computed.
Is this possible? Is there any way to re-render the template or even just re-render the entire component manually? How? If not, what is the simplest way to get the computed value or template re-rendered without a property in the binding?
How about that????
<dom-module id="my-component">
<template>
<style></style>
<p><span>[[str]]</span></p>
</template>
<script>
var MyComponent = Polymer({
is: "my-component",
properties: {
translations: {
type: Object,
notify: true,
value: {
"SOME_STRING": "Some String"
},
observer: '_Changed'
},
str: {
type: String,
value: "hello"
}
},
_Changed: function(){
this.set("str",this.translate(this.str));
},
translate: function (key) {
if (this.translations.hasOwnProperty(key)) {
return this.translations[key];
}
}
});
</script>

Polymer 1: How can I set up paper-checkbox label dynamically using a custom element

I want to set label/s of paper-checkbox elements through a custom element I have created.
This is how I am calling my custom element with the value set to a property called optionLabel which I want to display when checkbox renders on the screen.
<check-list optionLabel="My first checkbox"></check-list>
My custom element check-list looks like this:
<dom-module id="check-list">
<template>
<style>
:host {
display: block;
}
</style>
<paper-checkbox on-change="_checkChanged">{{optionLabel}}</paper-checkbox>
</template>
<script>
(function () {
'use strict';
Polymer({
is: 'check-list',
properties: {
optionLabel: {
type: String,
notify: true
}
},
_checkChanged: function (e) {
alert("State changed");
}
});
})();
</script>
</dom-module>
My goal is to reuse my custom element inside a dom-repeat layout and set values according to the requirement.
What is the correct way of doing this?
According to the documentation camelCase properties are "accessed" from outside the element like camel-case. The documentation states the following:
Attribute names with dashes are converted to camelCase property names
by capitalizing the character following each dash, then removing the
dashes. For example, the attribute first-name maps to firstName. The same mappings happen in reverse when converting property names to attribute names.
In other words, your code should have worked if you did the following instead:
<check-list option-label="My first checkbox"></check-list>
I got it to work! The variable (property) I was using previously was optionLabel, which did not work. Don't know what is the reason but when I changed it to optionlabel, i.e. all lowercase, it worked fine!
Not sure if above is the true solution to the problem I faced but it is working for me now :)
However, it will still be very helpful for many beginners like me if somebody please explain why optionLabel did not work.
So my code now changes to this
Custom element:
<dom-module id="check-list">
<template>
<style>
:host {
display: block;
}
</style>
<paper-checkbox on-change="_checkChanged">{{optionlabel}}</paper-checkbox>
</template>
<script>
(function () {
'use strict';
Polymer({
is: 'check-list',
properties: {
optionlabel: {
type: String,
notify: true
}
},
_checkChanged: function (e) {
if (e.target.checked) {
this.optionlabel = "Good to see you agree";
this.$.btnsubmit.disabled = false;
} else {
this.optionlabel = "Please agree to proceed";
this.$.btnsubmit.disabled = true;
}
}
});
})();
</script>
</dom-module>
And the call looks like:
<check-list optionlabel="My first checkbox"></check-list>

Updating an array in the controller scope from a partial

I am using an isteven-multi-select with a controller (ListController) that is using "$scope.mainCategories" for content that is populated by the "ticked" boolean value.
In the header of the application, I am using a select element to allow the user to select a single category (and then be forwarded to the list page). I am using this select element to toggle the ticked boolean value in $scope.mainCategories.
Both are using the same controller, although references separately through UI-Router (possible issue)
views: {
'header#index': {
templateUrl: 'header.html',
controller: "ListController"
},
'container#index': {
templateUrl: 'search.html',
controller: 'ListController'
},
}
then the isteven-multiselect and the select element are in the same partial - the functionality works - when on separate partials the functionality is broken.
Plunker
x might not be what you expect because you can't look for index of object in this line unless you're passing in the actual object:
var x = $scope.mainCategories.indexOf(item);
I assume you're trying to pass in something like:
{
category: "Adventure",
ticked: false
}
and to get the index, it won't work. You need to loop over the array and match the category, for example.
Your approach for modifying the outside array is fine, though.
See this example to see what I mean:
var people = [
{name: 'Shomz'},
{name: 'John'}
];
alert(people.indexOf({ name: 'John'})); // -1: the copy of object not found
alert(people.indexOf(people[1])); // 1: actual reference found
Scope update
To manually update the scope, either wrap the code in a $timeout callback, or use:
$scope.$apply();
$scope.update = function(item) {
item.ticked = true; // ?
};
$scope.mainCategories = [{
category: "Adventure",
ticked: false
},{category: "Fantasy",
ticked: false}];
Just have your function take the object you want to modify and pass that in from the view.

Backbone & Underscore: unable to pass model to template for evaluation

I'm having trouble with passing model data from a Backbone View to a template in Underscore. I want to pass an array into the template so I can evaluate using _.each.
My code is below:
templateSettings
_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g,
evaluate: /\{\{([\s\S]+?)\}\}/g
};
Interpolate is {{ }} and evaluate is {[ ]}. Unless my regex is incorrect
View
el: $('#assasinationBackbone'),
events: {
'click #newHitJob': 'addNewHitJob'
},
initialize: function() {
},
addNewHitJob: function() {
var hitMen = new HitManList();
var template = _.template($('#newHitJobTemplate').html());
hitMen.fetch({
success: function() {
$('#newHitJobForm').html(template(hitMen.toJSON()));
return hitMen; //CANNOT REMEMBER WHY I PUT THIS HERE (NO SIDE EFFECTS)
}
});
});
I did not define the template in the view as template: , but instead I defined it inside the addNewHitJob property.
1. Is this correct? I did this because I will have more than one template. The said template is below
Template (in Jade), I can translate to html if need be
.span4#newHitJobForm
script#newHitJobTemplate(type="text/template")
select#names
{[ _.each(hitman, function(name) { ]}
option(value="{{ name._id }}") {{ name.name }}
{[ }); ]}
2. From what I have seen, My problem is with passing hitman to the template, but I am uncertain. Is there something I am missing?
Your evaluate regex isn't right, you want:
evaluate: /\{\[(.+?)\]\}/g
Your evaluate regex is equivalent to your interpolate since [\S\s] should match anything just like . does.
And when you call an Underscore template, you need to give it an object with the names and values for the template, just handing it an array (hitMen.toJSON()) won't do anything useful; you need to give your serialized hitMen a name so that the template can refer to them:
$('#newHitJobForm').html(template({ hitMen: hitMen.toJSON() }));
and then in the template:
{[ _.each(hitMen, function(hitMan) { ]}
option(value="{{ hitMan.cat._id }}") {{ hitMan.name }}
{[ }); ]}
I had to guess about the hitMan.cat._id part.

Resources