How can I set class name dynamically? - polymer

I have understood from my last question here that string concatenate is not allowed with 0.9 and above (currently I am migrating to version 1.0).
I have to rather wrap every variable inside separate HTML element.
However there are times when I need to use a href or class attribute to be assigned with values dynamically. I cannot make it to work directly like the following:
Link text
since 1.0 won't allow string concatenation!
Please see the snippets below. I am trying to pass an attribute value from my index.html which in turn should replace the value in class attribute inside my custom element. But it is not working and I understand why.
<dom-module id="multi-color-bar-chart">
<template>
<div id="chart">
<p>{{title}}</p>
<div class="{{v1bg}}">
<!-- I want {{v1bg}} to be replaced by value sent from index.html -->
<span>{{value1}}</span>%
</div>
<div class="v2" style="background:#ffcc00;">
<span>{{value2}}</span>%
</div>
<div class="v3" style="background:#369925;">
<span>{{value3}}</span>%
</div>
<div class="clear"></div>
</div>
<div class="clear"></div>
</template>
<script>
(function () {
Polymer({
is: 'multi-color-bar-chart', //registration of element
properties: {
title: { type: String },
value1: { type: String },
value2: { type: String },
value3: { type: String },
v1bg: { type: String }
}
});
})();
</script>
</dom-module>
Here is the snippet in index.html
<multi-color-bar-chart
title="Annual"
value1="45.5"
value2="22.3"
value3="32.2"
v1bg="#ff0000">
...
...
</multi-color-bar-chart>
I am passing a hex code #ff0000 via v1bg attribute which I intend to actually replace the property inside the element.
I don't know yet if there is a work around to it. Might have used document.querySelector() but didn't try that yet. If there is a direct HTML approach that would be wonderful.

Try class$="{{v1bg}}", as this will bind to the class attribute rather than the class property.
https://www.polymer-project.org/1.0/docs/devguide/data-binding.html#attribute-binding

Related

VueJS - calling multiple image src as custom props

I have a small set of icons i want to call as a custom image prop depending on what type of item the component is. Code looks like this:
Vue.component('otherArticles', {
template: `
<!-- Component -->
<li>
<img :src="icon.text && icon.video" alt="icon">
<a :href="url">{{ Title }}</a>
</li>
`,
props: {
title: String,
url: String,
icon: [
{
text: "/resources/img/icons/text-icon.svg",
video: "/resources/img/icons/video-icon.svg"
}
]
}
});
Ideally in my html I would like to call them like this:
<!--Component with text icon-->
<other-articles
icon='text' <!-- how i'd like to call the text icon as img src -->
url="."
title="Text article title">
</other-articles>
<!--Component with video icon-->
<other-articles
icon='video' <!-- how i'd like to call the video icon as img src -->
url="."
title="Video article title">
</other-articles>
The img src binding is incorrect I know, i'm using it as an example of how i'm thinking it should be done, but I'm looking for any and all recommendations on how to do this correctly so I can call it the html as the example shows.
I only have these two icons and the src location for each may change but i would like to call it the same way even if i have to update the src location for either one in the future, keeping the html calls the same or similar. Any help would be appreciated. Thanks
First start by declaring your icon list as the following in your data function:
data() {
return {
iconList: {
text: '/resources/text.png',
video: '/resource/video.png',
}
};
}
Make sure to remove the list and rename the object, as you cannot have a prop and an entry in data with the same name. Then add your definition for icon to your props section as the following:
props: {
icon: {
type: String,
required: true,
},
},
This tells Vue to typecheck the prop as a string, and warn when it's not present or not a string.
Now you need to update your template function to use this new prop as an key to lookup the related icon:
template: `
<img :src="iconList[icon]"/>
`,
Now you can use your component as <comp icon="video"/>

How to change parent element property from child element?

How can I let a child element change the value of a property in the parent element with the ability to observe that change in the parent element
<link rel="import" href="paper-tree-node.html">
<dom-module id="paper-tree">
<template>
<div>
<paper-tree-node id="root" data="[[data]]" actions="[[actions]]" on-click='_handlePaperCheck' chapterIds={{chapterIds}}></paper-tree-node>
</div>
</template>
</dom-module>
<script>
Polymer({
is: 'paper-tree',
properties: {
chapterIds: {
type: Array,
value: [],
notify: true,
observer: "_chapterChanged"
}
},
_handlePaperCheck: function (e) {
let element = e.target.parentElement
if (element.checked) {
this.push('chapterIds', parseInt(element.id.substr(2)))
// console.info(this.chapterIds);
} else {
var index = this.chapterIds.indexOf(element.id);
this.splice('chapterIds', index, 1)
// console.info(this.chapterIds);
}
},
_chapterChanged: function () {
console.log(this.chapterIds)
// this.$.root.chapterIds = this.chapterIds
}
})
noting that paper-tree-node is a child element hosts a paper-check inside it's template, the purpose of this is to harvest the clicked paper-tree-node id attr and push it to the chapterIds property.
Problem is that _chapterChanged wont fire when i click on any checkbox
I am attaching a sample project since this cannot be posted on somthing like jsbin, here is a gdrive zip folder for the project https://drive.google.com/file/d/1yCeXkZu8Yp-8GUgadGHIfeP5w5uyI12J/view?usp=sharing
You're using the right thinking, but not the entire way.
notify: true, should be stated in your child element paper-tree-node under the property chapterIds, and not under your paper-tree element. I made this mistake too when I began with Polymer.
Also, whenever Polymer sees camelCase variables, it assumes the variable contains dashes:
<paper-tree-node id="root" data="[[data]]" actions="[[actions]]" on-click='_handlePaperCheck' chapterIds={{chapterIds}}></paper-tree-node>
... should be ...
<paper-tree-node id="root" data="[[data]]" actions="[[actions]]" on-click='_handlePaperCheck' chapter-ids={{chapterIds}}></paper-tree-node>
... where I switched the property chapterIds to chapter-ids. I rarely use camelCase variables when creating a new element because this mistake is so easy to make.
You can do this with an event or with data binding.

Complete example of Polymer Two Way Binding

The polymer documentation has the following two way binding example:
<script>
Polymer({
is: 'custom-element',
properties: {
someProp: {
type: String,
notify: true
}
}
});
</script>
...
<!-- changes to "value" propagate downward to "someProp" on child -->
<!-- changes to "someProp" propagate upward to "value" on host -->
<custom-element some-prop="{{value}}"></custom-element>
I'm looking for a complete example that includes the design of the child, programmatic and interactive events the can cause upward and downward propagation of the `{{value}} property, and a demo of of the complete setup / example.
Here are some examples on js fiddle that demonstrate different ways of binding:
Two-way binding:
https://jsfiddle.net/tej70osf/
One-way binding: notify is not set on value property of the child element:
https://jsfiddle.net/tej70osf/1/
One-way binding: notify is set to true true on value property of the child element however the value property is bound using square brackets [[value]] instead of {{value}}:
https://jsfiddle.net/tej70osf/2/
Hope that helps
<dom-module id="user-demo">
<template>
<paper-input label="FIRST NAME" value="{{firstName}}"></paper-input>
</template>
</dom-module>
<user-demo></user-demo>
In your javascript code:
Polymer({
is: 'user-demo',
properties: {
firstName: {
type: String,
value: 'John',
notify: true
}
}
});
Check out the following fiddle for the full example:
https://jsfiddle.net/meenakshi_dhanani/6ffwh0qv/
I tried to use more polymer elements and two way binding. Hope it helps

Polymer 1.0 strange behaviour on properties

I'm just learning polymer (1.0) so please bear with me.
I'm using express.js to return some array of JSON.stringified items and for-each them, so the result is as follows (in HTML):
<fighter-profile fighter="{"country":"USA","countryFullName":"United States","name":"Frank Mir","nickname":"","zuffa_record":{"wins":"15","losses":"9","draws":0,"no_contest":0}}"></fighter-profile>
it seems ugly as hell, but that's json.
Here's my component:
<dom-module id="fighter-profile">
<template>
<div>
<paper-item>
<paper-item-body two-line>
<div>{{fighter.name}}</div>
<div secondary>{{nickname}}</div>
<div>
<paper-button raised on-click="handleClick">Show nickname</paper-button>
</div>
</paper-item-body>
</paper-item>
</div>
<br />
<hr />
<br />
</template>
<script>
Polymer({
is: 'fighter-profile',
properties: {
fighter: Object,
nickname: {
type: String,
value: 'testing'
}
},
ready: function() {
this.nickname = (this.fighter.nickname !== '') ? this.fighter.nickname : '... the dude has no nickname!';
},
handleClick: function() {
alert(this.nickname);
}
});
</script>
</dom-module>
Now, the funny part: the name gets displayed properly, while where I have the <div secondary>{{nickname}}</div>, the result in HTML is literally {{nickname}}; however, if I click on button, I get the correct value.
What am I missing here?
UPDATE:
I've googled some stuff, and replaced ready method with created and, of course, it didn't work, since created I think is part of Polymer 0.5 version. Then I switched back to ready method and now everything works as expected. Very odd.
What seems to be the problem? Some caching gone wrong? a bug?
UPDATE 2:
I've changed some stuff again and it doesn't work, but now I've figured out how to replicate the mistake. So, this piece of code DOESN'T work correctly:
<div secondary>The dude is also known as {{nickname}}</div>
the result is literally "{{nickname}}"
However, this works correctly:
<div secondary>The dude is also known as <span>{{nickname}}</span></div>
the result is the actual nickname.
So, putting properties in span tag renders it correctly. What's going on?
There's a few things I think I can help you with here. First, you can make your JSON much more readable by using single quotes for your attributes. Additionally, you can include white space, if you are hard-coding the JSON:
<fighter-profile
fighter='{
"country":"USA",
"countryFullName":"United States",
"name":"Frank Mir",
"nickname":"",
"zuffa_record":{
"wins":"15",
"losses":"9",
"draws":0,
"no_contest":0
}
}'></fighter-profile>
Next, I'm going to assume that the JSON is actually not hard-coded, and bound to another data source. I make this assumption because it seems like your fighter property is not available in ready, as you are expecting it to be. A common issue I see in cases such as this is something like the following:
<template is="dom-repeat" items="{{data}}" as="fighter">
<fighter-profile fighter="{{fighter}}"></fighter-profile>
</template>
The thing to keep in mind in the above case is that <fighter-profile> is created, readied, and attached to the DOM before the parent element assigns fighter to its fighter property.
To remedy this, you can make use of observers which perform tasks automatically when the data gets loaded into a property:
<script>
Polymer({
is: 'fighter-profile',
properties: {
fighter: Object,
nickname: {
type: String,
value: 'testing'
}
},
observers: [
// This tells Polymer to watch `fighter` and fire the
// _fighterUpdated method only after `fighter` receives
// a value **other than undefined.**
'_fighterUpdated(fighter)'
],
_fighterUpdated: function(fighter) {
this.nickname = (this.fighter.nickname || '... the dude has no nickname!');
}
});
</script>
Next, binding properties to HTML. When you bind to HTML contents, such as with <div>{{property}}</div>, what Polymer (currently) does behind the scenes is bind property directly to div.innerText. Polymer also only checks the first two characters of innerText to see if it's a {{ or [[, and does not do anything if it doesn't find them.
The Polymer team is working to make binding more robust, but so far as I know they haven't announced any concrete plans or timelines. For the time being, the solution is as you've discovered, just wrap an inline binding in <span> =)

Pass HTML element with attribute via an HTML element's attribute

I have an HTML element which I annotated with an angular directive, in this case translate from ngTranslate. ngTranslate gives the option to interpolate values in the translation string at runtime with arbitrary angular expressions (and even a subcompile option for compiling containes directives).
Now my problem is I would like to interpolate {{name}} in the message Hello {{name}} with a custom directive <test blah="'Robert'"></test>. That is, in the end I expect to get the following HTML as output from the example below:
<body>
<div ng-controller="Ctrl">
<p translate="VARIABLE_REPLACEMENT" translate-values="{ name: '<test blah="'Test'"></test>' }" translate-compile>Hi <span>Hello Robert</span></p>
<span>Hello Robert</span>
</div>
</body>
JS Code:
var translations = {
VARIABLE_REPLACEMENT: 'Hi, {{name}}'
};
var app = angular.module('myApp', ['pascalprecht.translate']);
app.config(['$translateProvider', function ($translateProvider) {
// add translation table
$translateProvider
.translations('en', translations)
.preferredLanguage('en');
}]);
app.controller('Ctrl', ['$scope', function ($scope) {
}]);
app.directive('test',function () {
return {
restrict: 'E',
template: '<span>Hello {{blah}}</span>',
replace: true,
scope: {
blah: '='
}
};
});
HTML (relevant part):
<body>
<div ng-controller="Ctrl">
<p translate="VARIABLE_REPLACEMENT" translate-values="{ name: '<test blah="'Robert'"></test>' }" translate-compile></p>
<test blah="'Robert'"></test>
</div>
</body>
You can play with it in this Plunker: http://plnkr.co/edit/FQZS4eaZVm52sbVzQ1xb?p=preview
The problem: Passing an HTML element through the attribute of another HTML element results in parsing problems with ". I tried to escape the "(\") of the attribute of the element that is passed in but that doesn't seem to work either. How can I pass an HTML element with attributes through the attribute of another HTML element?