In this example i'm expecting it to say "hello world" but the world isn't picked up from the saying attribute.
(function () {
'use strict';
$(function () {
// Set up a route that maps to the `filter` attribute
can.route(':filter');
// Render #app-template
$('#app').html(can.view('appTemplate', {}));
// Start the router
can.route.ready();
});
can.Component.extend({
tag: "say",
scope: {
saying: function(){
return this.attr('saying')
},
greeting: 'salutations'
},
template: can.view("sayTemplate")
});
})();
Templates:
<div id="app"></div>
<script id="appTemplate" type="text/mustache">
<b>Hello</b>
<say saying="world"></say>
</script>
<script id="sayTemplate" type="text/mustache">
<b>{{saying}}.</b> <i>{{greeting}}</i>
</script>
You need to tell the component that you want to access the attributes plain value like this:
can.Component.extend({
tag: "app-say",
scope: {
saying: '#',
greeting: 'salutations'
},
template: can.view("sayTemplate")
});
See this Fiddle. What you eventually might want to do use an observable attribute from your application state instead of the plain string value. This might look like:
var appState = new can.Map({
name: 'World'
});
$(function () {
// Set up a route that maps to the `filter` attribute
can.route(':filter');
// Render #app-template
$('#app').html(can.view('appTemplate', appState));
// Start the router
can.route.ready();
});
can.Component.extend({
tag: "app-say",
scope: {
greeting: 'salutations'
},
template: can.view("sayTemplate")
});
And a template like:
<div id="app"></div>
<script id="appTemplate" type="text/mustache">
<b>Hello</b>
<app-say saying="{name}"></app-say>
<div><input type="text" can-value="name"></div>
</script>
<script id="sayTemplate" type="text/mustache">
<b>{{saying}}.</b> <i>{{greeting}}</i>
</script>
This also creates a cross-bound input field that will update the name everywhere whenever you update the text field. Fiddle is here.
Related
<!DOCTYPE html>
<html lang="en">
<head>
<script src="js/vue.js"></script>
<meta charset="UTF-8">
<title>V-for example</title>
</head>
<body>
<script type="x/template" id="testTemplate">
<div><h1>{{name}}</h1>
<p>{{Age}}</p></div>
</script>
<div id="example">
<div id="filler">
<template v-for="person in people">
<test-component name="{{person.name}}"></test-component>
</template>
</div>
</div>
<script>
var newComponent = Vue.extend({
template: '#testTemplate',
props: ['name'],
data: function () {
return {
Age: 1010
}
}
});
Vue.component('test-component', newComponent);
new Vue({
el: '#example',
data: {
people: [{
name: 'jason',
age: 15,
complete: true
}, {
name: 'Jeremy',
age: 20,
complete: false
}]
},
ready: function () {
var divoutput = document.querySelector('#filler');
alert(divoutput.innerHTML);
len = this.$data.people.length;
for (i = 0; i < len; i += 1) {
var nameT = this.$data.people[i].name;
divoutput.innerHTML += '<test-component name="' + nameT + '"></test-component>';
}
},
});
</script>
</body> </html>
I'm trying to take all of the people in the Vue data array and inject it into a component and add it to a innerHTML of a div during the Vue.ready() function. I show that result is being injected in to the "filler" array but the components them selves are not being rendered properly. If I make a manual instance of my component it works fine.
You shouldn't try to add Vue component using innerHTML. That's managing the DOM yourself, just let Vue do that on its own. Here is a fiddle:
https://jsfiddle.net/xccjsp4b/
I changed the script template to a div because I'm not certain you can use the script tag like that (although I could be wrong). Then you just use a v-for to loop through the people and pass the relevant data as properties. If each person is going to have their own age, you want it to be a property not a data variable.
Also, use the shorthand binding of :name="person.name" rather than name="{{person.name}}". The : tells Vue to evaluate the expression.
How I can access an element inside dom-if condition?
That's part of my template:
<template>
...
<template is="dom-if" if="{{_displayUserLevelBadge(level)}}">
<div class="profileUserLevelContainer">
<iron-icon id="userLevelBadge" class="icon-20" icon="chat:verified-user"></iron-icon>
<span class="profileUserLevel">{{userLevelString}}</span>
</div>
</template>
...
</template>
I need to access #userLevelBadge in Javascript like that:
Look in the ready method.
Polymer({
is: 'custom-element',
properties: {
level: {
type: String,
value: null
},
userLevelString: {
type: String,
value: ''
}
},
ready: function() {
var userLevelBadge = this.$$('#userLevelBadge'); //return undefined
},
_displayUserLevelBadge: function(){
//not including my code
//Just returning true for simplicity
return true;
}
}
But it does not work. The condition is meet, and the HTML inside dom-if is displayed, but i can't access it using this.$$(selector), as specified in the Wiki.
Fiddle: https://jsfiddle.net/Fr0z3n/sntyw50u/
Wrap the code in this.async() to give Polymer some time to stamp the template content.
Is this possible to have data binding inside an inline script tag? For example:
<script src="{{url}}" class="{{klass}}"></script>
Polymer({
is: "test-app",
ready: function() {
url = "http://google.com/js/some-file.js",
klass = "script-class"
}
});
Based on the Polymer 1.0 Data Binding docs, I could not come up with anything better.
I have edited this post to 100% clarity of what I want to achieve. I want to use Strip Embedded Checkout:
<form action="" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="pk_test_blahblah"
data-amount="2000"
data-name="Demo Site"
data-description="2 widgets ($20.00)"
data-image="/128x128.png">
</script>
</form>
Mason's answer and Anthony's clue led me to this:
<dom-module id="my-app>
<template>
<form action="" method="POST">
<script
src$="{{url}}" class$="{{klass}}"
data-key$="{{key}}"
data-amount$="{{total}}"
data-name$="{{dname}}"
data-description="2 widgets ($20.00)"
data-image="/128x128.png">
</script>
</form>
</template>
<script>
Polymer({
is: "my-app",
properties: {
selection: {
type: String,
observation: "selectionChanged"
}
},
ready: function() {
this.url = 'https://checkout.stripe.com/checkout.js';
this.klass = 'stripe-button';
this.key = 'pk_test_blahblah';
this.dname = 'Demo';
// this.total = "333"; // this value is not static
},
selectionChanged: function () {
if (true) {
this.total = 50; // I need this to assign to "{{total}}" in the template.
}
};
</script>
</dom-module>
How can I get the value of this.total to be assigned to data-amount in the script tag of Stripe's?
See Plunkr
I did a Plunk and it seems it's not possible to do this.
<dom-module id="my-element">
<template>
<script src="{{url}}"></script>
Try to load <span>{{name}}</span>
</template>
<script>
Polymer({
is: 'my-element',
ready: function() {
this.name = 'JQuery';
this.url = 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js';
this.async(function() {
this.name = 'AngularJs';
this.url = 'https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js';
}, 5000);
}
});
</script>
</dom-module>
The first loading works but when the bind value has changed, Polymer does not create a new script tag for you. You can create a script tag by using the DOM.
Edited:
Initializing the script tag's attributes without "ready" method.
<template>
<script src="{{_url}}"></script>
</template>
<script>
Polymer({
is: 'my-element',
properties: {
_url: {
type: String,
value: 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js'
}
}
})
</script>
Or using hosted attributes
<template>
<script src="{{url}}"></script>
Try to load <span>{{name}}</span>
</template>
<script>
Polymer({
is: 'my-element',
hostAttributes: {
url: {
type: String
}
}
})
</script>
and in the parent element:
<my-element url="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></my-element>
By using hostAttributes you'll see the url in the DOM.
I use a knockoutjs with templating plugin (Using Underscore Template with Knockout using interpolate due to asp.net)
If i have a header and a list:
<ul data-bind="template: { name: 'people' }"></ul>
<script type="text/html" id="people">
<h2>{{= hdr}}</h2>
{{ _.each(people(), function(item) { }}
<li>{{=item.name }} ({{=item.age }})</li>
{{ }); }}
</script>
also a button
<button id="bindclick">Click</button>
and a ja code where i use knockout:
ko.applyBindings({
hdr: "People",
people: ko.observableArray([{name:"name1",age: 45},{name:"name2",age: 33}])
});
How to do, that template value can be change with clicking a button instead of "Uncaught Error: You cannot apply bindings multiple times to the same element."?:
$("#bindclick").click(function() {
ko.applyBindings({
hdr: "People2",
people: ko.observableArray([{name:"name1",age: 45}])
});
});
Thanks
You should only need to call applyBindings once with a model object.
Later on in your click handler, you would simply update your model.
For example:
var theModel = {
hdr: ko.observable('People'),
people: ko.observableArray([{name:"name1",age: 45},{name:"name2",age: 33}])
};
ko.applyBindings(theModel);
$('#bindclick').click(function () {
theModel.hdr('People2');
theModel.people([{name:"name1",age: 45}]);
});
Updating the model should update your previously bound content.
I have a simple Handlebars helper which simply formats a money value. The helper works property when I test with static data, but not when I load data asynchronously. In other words, {{totalBillable}} will output the expected amount, but {{money totalBillable}} will output zero. But only when the data is loaded via an ajax call. What the heck am I doing wrong?
I've tried to pare the code down as much as possible, and also created a jsfiddle here:
http://jsfiddle.net/Gjunkie/wsZXN/2/
This is an Ember application:
App = Ember.Application.create({});
Here's the handlebars helper:
Handlebars.registerHelper("money", function(path) {
var value = Ember.getPath(this, path);
return parseFloat(value).toFixed(2);
});
Model:
App.ContractModel = Ember.Object.extend({});
App Controller:
App.appController = Ember.Object.create({
proprietor: null,
});
Contracts Controller (manages an array of contracts):
App.contractsController = Ember.ArrayController.create({
content: [],
totalBillable: function() {
var arr = this.get("content");
return arr.reduce(function(v, el){
return v + el.get("hourlyRate");
}, 0);
}.property("content"),
When the proprietor changes, get new contract data with an ajax request. When getting data asynchronously, the handlebars helper does not work.
proprietorChanged: function() {
var prop = App.appController.get("proprietor");
if (prop) {
$.ajax({
type: "POST",
url: '/echo/json/',
data: {
json: "[{\"hourlyRate\":45.0000}]",
delay: 1
},
success: function(data) {
data = data.map(function(item) {
return App.ContractModel.create(item);
});
App.contractsController.set("content", data);
}
});
}
else {
this.set("content", []);
}
}.observes("App.appController.proprietor")
});
If I use this version instead, then the Handlebars helper works as expected:
proprietorChanged: function() {
var prop = App.appController.get("proprietor");
if (prop) {
var data = [{
"hourlyRate": 45.0000}];
data = data.map(function(item) {
return App.ContractModel.create(item);
});
App.contractsController.set("content", data);
}
else {
this.set("content", []);
}
}.observes("App.appController.proprietor")
View:
App.OverviewTabView = Ember.TabPaneView.extend({
totalBillableBinding: "App.contractsController.totalBillable"
});
Kick things off by setting a proprietor
App.appController.set("proprietor", {
ID: 1,
name: "Acme"
});
Template:
<script type="text/x-handlebars">
{{#view App.OverviewView viewName="overview"}}
<div class="summary">
Total Billable: {{totalBillable}}<br/>
Total Billable: {{money totalBillable}}<br/>
</div>
{{/view}}
</script>
when using a helper, handlebars does not emit metamorph tags around your helper call. this way, this part of the template is not re-rendered because there is no binding
to manually bind part of a template to be re-rendered, you can use the bind helper:
<script type="text/x-handlebars">
{{#view App.OverviewView viewName="overview"}}
<div class="summary">
Total Billable: {{totalBillable}}<br/>
Total Billable: {{#bind totalBillable}}{{money this}}{{/bind}}<br/>
</div>
{{/view}}
</script>