In a jsviews based app, I have a data object that contains a type attribute (actually a server type).
I'd like to convert it and append a suffix to pass to a tmpl inclusion.
Let's say I have :
$.views.converters({
"serverSideTypeToLocalType": function(serverSideType) {
switch(serverSideType) {
case "server-side-type1":
return "type1";
case "server-side-type2":
return "type2";
case "server-side-type3":
return "type3";
default:
throw "Invalid type";
}
}
});
I also have templates :
<script type="text/x-jsrender" id"type1-edit">
template for editing type 1
</script>
<script type="text/x-jsrender" id"type1-view">
template for viewing type 1
</script><script type="text/x-jsrender" id"type2-edit">
template for editing type 2
</script>
<script type="text/x-jsrender" id"type2-view">
template for viewing type 2
</script><script type="text/x-jsrender" id"type3-edit">
template for editing type 3
</script>
<script type="text/x-jsrender" id"type3-view">
template for viewing type 3
</script>
My data object is :
var data = { MyObjects : [
{
"ServerSideType": "server-side-type1",
"IsEditing" : true
},{
"ServerSideType": "server-side-type2",
"IsEditing" : false
}] };
How to construct a main template that includes dynamically the correct template based on ServerSideType and IsEditing properties ?
I tried :
<div>
{^{for MyObjects}}
{^{include ^tmpl=({serverSideTypeToLocalType:ServerSideType}+ "-" + IsEditing ? "edit":"view")/}}
{{/for}}
</div>
but it fails with a weird error Cannot read property 'bd' of undefined.
Here is a reproductible sample:
(function($) {
$(function() {
$.views.converters({
"serverSideTypeToLocalType": function(serverSideType) {
switch (serverSideType) {
case "server-side-type1":
return "type1";
case "server-side-type2":
return "type2";
case "server-side-type3":
return "type3";
default:
throw "Invalid type";
}
}
});
var data = {
MyObjects: [{
"ServerSideType": "server-side-type1",
"IsEditing": true
}, {
"ServerSideType": "server-side-type2",
"IsEditing": false
}]
};
var tmpl = $.templates("#main");
tmpl.link("#container", data);
});
})(jQuery);
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jsviews/0.9.90/jsviews.min.js"></script>
<script type="text/x-jsrender" id="main">
<div>
{^{for MyObjects}}
<p>Object n° {^{:#index +1}}</p>
{^{include ^tmpl=({serverSideTypeToLocalType:ServerSideType}+ "-" + IsEditing ? "edit":"view")/}}
{{/for}}
</div>
</script>
<script type="text/x-jsrender" id="type1-edit">
<div>
template for editing type 1
</div>
</script>
<script type="text/x-jsrender" id="type1-view">
<div>
template for viewing type 1
</div>
</script>
<script type="text/x-jsrender" id="type2-edit">
<div>
template for editing type 2
</div>
</script>
<script type="text/x-jsrender" id="type2-view">
<div>
template for viewing type 2
</div>
</script>
<script type="text/x-jsrender" id="type3-edit">
<div>
template for editing type 3
</div>
</script>
<script type="text/x-jsrender" id="type3-view">
<div>
template for viewing type 3
</div>
</script>
<div id="container">Loading ...</div>
You can't nest a {:...} tag within the markup of a {{...}} tag.
I would suggest using a helper, rather than a converter:
{^{include ^tmpl="#" + ~serverToLocal(ServerSideType) + "-" + (IsEditing ? "edit":"view")/}}
You can also use a data-linked element:
<span data-link='{include ^tmpl="#" + ~serverToLocal(ServerSideType)+ "-" + (IsEditing ? "edit" : "view")}'></span>
(function($) {
$(function() {
function serverToLocal(serverSideType) {
switch (serverSideType) {
case "server-side-type1":
return "type1";
case "server-side-type2":
return "type2";
case "server-side-type3":
return "type3";
default:
throw "Invalid type";
}
}
var data = {
MyObjects: [{
"ServerSideType": "server-side-type1",
"IsEditing": true
}, {
"ServerSideType": "server-side-type2",
"IsEditing": false
}]
};
var tmpl = $.templates("#main");
tmpl.link("#container", data, {serverToLocal: serverToLocal});
});
})(jQuery);
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jsviews/0.9.90/jsviews.min.js"></script>
<script type="text/x-jsrender" id="main">
<div>
{^{for MyObjects}}
<p>Object n° {^{:#index +1}}</p>
<input data-link="ServerSideType" />
<input data-link="IsEditing" type="checkbox"/>
{^{include ^tmpl="#" + ~serverToLocal(ServerSideType) + "-" + (IsEditing ? "edit":"view")/}}
{{/for}}
</div>
Two:
<div>
{^{for MyObjects}}
<p>Object n° {^{:#index +1}}</p>
<span data-link='{include ^tmpl="#" + ~serverToLocal(ServerSideType)+ "-" + (IsEditing ? "edit" : "view")}'></span>
{{/for}}
</div>
</script>
<script type="text/x-jsrender" id="type1-edit">
<div>
template for editing type 1
</div>
</script>
<script type="text/x-jsrender" id="type1-view">
<div>
template for viewing type 1
</div>
</script>
<script type="text/x-jsrender" id="type2-edit">
<div>
template for editing type 2
</div>
</script>
<script type="text/x-jsrender" id="type2-view">
<div>
template for viewing type 2
</div>
</script>
<script type="text/x-jsrender" id="type3-edit">
<div>
template for editing type 3
</div>
</script>
<script type="text/x-jsrender" id="type3-view">
<div>
template for viewing type 3
</div>
</script>
<div id="container">Loading ...</div>
Related
I have an array of objects which has a field to indicate whether its properties should be displayed:
[{
state: true
},
{
state: false
},
{
state: false
}]
And I use Polymer iron-collapse's "opened" field to bind with state in order to collapse it.
This works in Polymer 0.5, but it fails in 1.0. Also, it works if I directly pass a boolean property - just not with an object.
When I say "doesn't work", I mean that the collapsing doesn't happen.
What did I fail to migrate properly? Or is this a bug in iron-collapse?
This Works:
(Using an Array of Boolean)
demo.html:
<html>
<head>
<link rel="import" href="iron-collapse-demo.html">
</head>
<body>
<iron-collapse-demo states='[ true, false, false ]'></iron-collapse-demo>
</body>
</html>
iron-collapse-demo.html:
<html>
<head>
<script src="../bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../bower_components/iron-collapse/iron-collapse.html">
</head>
<body>
<dom-module id="iron-collapse-demo">
<style>
</style>
<template>
<template is="dom-repeat" items="{{states}}">
<span on-tap="collapseToggle"><+></span>
<iron-collapse opened="{{item}}">
<div>Hello collapse!</div>
</iron-collapse>
</template>
</template>
</dom-module>
</body>
<script src="iron-collapse-demo.html.0.js"></script>
</html>
iron-collapse-demo.html.0.js:
Polymer({
'is': 'iron-collapse-demo',
'properties': {
'states': Array
},
'ready': function() {
},
'collapseToggle': function(event, detail, sender) {
event.model.item = !event.model.item;
},
});
This doesn't work:
(Using an Array of Object with a Boolean property)
demo.html
<html>
<head>
<link rel="import" href="iron-collapse-demo.html">
</head>
<body>
<iron-collapse-demo nums='[ {"state": true}, {"state": false}, {"state": false} ]'></iron-collapse-demo>
</body>
</html>
iron-collapse-demo.html:
<html>
<head>
<script src="../bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../bower_components/iron-collapse/iron-collapse.html">
</head>
<body>
<dom-module id="iron-collapse-demo">
<style>
</style>
<template>
<template is="dom-repeat" items="{{nums}}">
<span on-tap="collapseToggle"><+></span>
<iron-collapse opened="{{item.state}}">
<div>Hello collapse!</div>
</iron-collapse>
</template>
</template>
</dom-module>
</body>
<script src="iron-collapse-demo.html.0.js"></script>
</html>
iron-collapse-demo.html.0.js:
Polymer({
'is': 'iron-collapse-demo',
'properties': {
'nums': Array
},
'ready': function() {
},
'collapseToggle': function(event, detail, sender) {
var num = event.model.item;
num.state = !num.state;
},
});
I found a hack/workaround, though I'm not convinced this should be the only way that works..
I wrapped the span and iron-collapse inside a div so that I can use a querySelector and toggle() the collapse.
iron-collapse-demo.html:
<template is="dom-repeat" items="{{nums}}">
<div>
<span on-tap="collapseToggle"><+></span>
<iron-collapse opened="{{item.state}}">
<div>Hello collapse!</div>
</iron-collapse>
</div>
</template>
iron-collapse-demo.html.0.js:
new collapseToggle:
'collapseToggle': function(event, detail, sender) {
// event.model.item.state = !event.model.item.state;
event.currentTarget.parentElement.querySelector('iron-collapse').toggle();
}
Try:
<iron-collapse horizontal opened$="[[item.state]]">
...
</iron-collapse>
HTML booleans are true when the attribute is present, not if the value of the attribute is true. Binding the attribute instead of value means Polymer outputs the attribute name when true but nothing for false.
I can not understand why and what this error is there - du you know why?
Update: I am running this in an nginx docker container.
Error message:
Uncaught Error: Parse Error: Line 10: Unexpected token ILLEGAL
at http://x.x.x.x/scripts/example.js:10:undefined
enter code here... R OTHER DEALINGS IN THE SOFTW
index.html
<!DOCTYPE html>
<html>
<head>
<title>Hello React</title>
<!-- Not present in the tutorial. Just for basic styling. -->
<link rel="stylesheet" href="css/base.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/JSXTransformer.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
</head>
<body>
<div id="content"></div>
<script type="text/jsx;harmony=true" src="scripts/example.js"></script>
</body>
</html>
script/example.js
var Simple = React.createClass({
getInitialState: function(){
return { count: 0 };
},
handleMouseDown: function(){
alert('I was told: ' + this.props.message);
this.setState({ count: this.state.count + 1});
},
render: function(){
return <div>
<div className="clicker" onMouseDown={this.handleMouseDown}>
Give me the message!
</div>
<div className="message">Message conveyed
<span className="count">{this.state.count}</span> time(s)</div>
</div>
;
}
});
React.render(<Simple message="Keep it Simple"/>,
document.body);
I run in NGINX no problem, I doubt this is an issue, but you never know if it's somehow a JSX compiler issue. Can you try the below and see if it's the same result in your environment?
var Simple = React.createClass({
getInitialState: function(){
return { count: 0 };
},
handleMouseDown: function(){
alert('I was told: ' + this.props.message);
this.setState({ count: this.state.count + 1});
},
render: function(){
render (
<div>
<div className="clicker" onMouseDown={this.handleMouseDown}>
Give me the message!
</div>
<div className="message">Message conveyed
<span className="count">{this.state.count}</span> time(s)</div>
</div>
)
}
});
React.render(<Simple message="Keep it Simple"/>,
document.body);
Problem:
nginx was caching
Solution:
Set nginx.conf setting to "expires off;"
In below ExamppleController function a value is entered into message variable local storage. For the first time value is getting stored but when entered again value is not getting stored. When browser cache is cleared then value is stored again and second time no value is getting stored.
Mystorage.html
<html>
<head>
<script src="angular.min.js"></script>
<script src="ngStorage.min.js"></script>
<script>
var example = angular.module("example", ["ngStorage"]);
example.controller("ExampleController", function($scope,$rootScope,$window,$localStorage,$location) {
$scope.save = function() {
$rootScope.newq=$scope.name;
$scope.$apply();
**$localStorage.message = $scope.name;**
console.debug($localStorage.message);
$window.location.href = 'nextstorage.html';
}
});
</script>
</head>
<body ng-app="example">
<div ng-controller="ExampleController">
<input type="text" ng-model="name"/>
<button ng-click="save()">Save</button>
<br>
{{data}}
</div>
</body>
</html>
NextStorage.html
<html>
<head>
<script src="angular.min.js"></script>
<script src="ngStorage.min.js"></script>
<script>
var example = angular.module("example", ["ngStorage"]);
example.controller("ExampleController", function($scope,$window,$localStorage,$location) {
$scope.data1 = $localStorage.message;
});
</script>
</head>
<body ng-app="example">
<div ng-controller="ExampleController">
<span>{{data1}}</span>
</div>
</body>
</html>
You should really be doing things the AngularJS way. I think this is where the disconnect happens.
See the following code:
<html>
<head>
<script src="angular.min.js"></script>
<script src="ngStorage.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.13/angular-ui-router.min.js"></script>
<script>
var example = angular.module("example", ["ngStorage", "ui.router"]);
example.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('1', {
url: '/1',
templateUrl: 'templates/1.html',
controller: 'FirstController'
})
.state('2', {
url: '/2',
templateUrl: 'templates/2.html',
controller: 'SecondController'
});
$urlRouterProvider.otherwise('/1');
});
example.controller("FirstController", function($scope,$localStorage,$location) {
$scope.save = function() {
$localStorage.message = $scope.name;
$location.path("/2");
}
});
example.controller("SecondController", function($scope,$localStorage,$location) {
$scope.data1 = $localStorage.message;
});
</script>
</head>
<body ng-app="example">
<div ui-view></div>
<script id="templates/1.html" type="text/ng-template">
<div>
<input type="text" ng-model="name"/>
<button ng-click="save()">Save</button>
<br>
</div>
</script>
<script id="templates/2.html" type="text/ng-template">
<div>
<span>{{data1}}</span>
</div>
</script>
</body>
</html>
You'll notice I'm using routes and navigating between them using the $location provider. The $localStorage works fine when doing it this way.
Read up on the ui-router or ngRoute.
Regards,
I've just started out using backbone. I want to apply a view to a button, but when I open my file in the browser there is nothing there.
Why isn't the button being rendered?
HTML:
<!-- Scripts -->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript" src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<script type="text/javascript" src="http://documentcloud.github.com/backbone/backbone-min.js"></script>
<script type="text/javascript" src="views/BaseButtonView.js"></script>
</head>
<body>
<script type="text/template" id="button-test">
<div id="test-buttons">
<button class="cta-ajax">
<p>send message</p>
<div class="spinner-container"></div>
</button>
</div>
</script>
</body>
</html>
View:
$(document).ready(function(){
var ButtonView = Backbone.View.extend({
el: $(".cta-ajax"),
template: _.template($("#button-test").html()),
initialize: function(){
console.log("Started!");
},
render: function() {
this.$el.html(this.template());
console.log("rendered");
return this;
}
});
var TView = new ButtonView();
});
You have two issues with your code. Here is a working jsfiddle: http://jsfiddle.net/cj4zkyow/1/
Issue 1:
Aside from implementing the initialize function, you also need to call render within initialize. Otherwise you have to call render manually.
Issue 2:
Second issue is that you set the el attribute of your view to .cta-ajax, but the element does not exist. It is part of your template. The el attribute is the element that your view gets appended to. So you need to use something that exists in the DOM.
HTML:
// Need a element to append view to.
<div id="test"></div>
<script type="text/template" id="button-test">
<div id="test-buttons">
<button class="cta-ajax">
<p>send message</p>
<div class="spinner-container"></div>
</button>
</div>
</script>
Javascript:
$(document).ready(function(){
var ButtonView = Backbone.View.extend({
// If you specify, el, it should be an element in the DOM, not in your template.
el: $("#test"),
template: _.template($("#button-test").html()),
initialize: function(){
// Need to call render in initialize function to render view.
this.render();
},
render: function() {
this.$el.html(this.template());
return this;
}
});
var TView = new ButtonView();
});
With the latest stable version of Handlebar, I'm trying to display the site name while iterating through each children. The output of the code below is:
5
Stackoverflow
One -
Two -
Can handlebars retrieve the site name by walking up while rendering the children?
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<script src="handlebars.js"></script>
<script>
$(document).ready(function() {
var source = $('#entry-template').html();
var template = Handlebars.compile(source);
var context = {
site: {
age: 5,
name: 'Stackoverflow',
children: [
{
name: 'One'
},
{
name: 'Two'
}
]
}
};
$('div#output').html(template(context));
});
</script>
</head>
<body>
<div id="output"></div>
<script id="entry-template" type="text/x-handlebars-template">
<div>{{site.age}}</div>
<div>{{site.name}}</div>
{{#each site.children}}
<div>{{name}} - {{site.name}}</div>
{{/each}}
</script>
</body>
</html>
Try doing {{../site.name}} in your loop. The ../ Handlebars syntax allows access of the parent scope.