Having a array like below
var arrNames = ["Stackoverflow","StackExchange","Webmaster","Programmers"];
how should a template look for working with mustache.js javascript template. I tried below but no clues
{{#}}{{key}}{{/}}
From the documentation:
When looping over an array of strings, a . can be used to refer to the current item in the list.
Template:
{{#musketeers}}
* {{.}}
{{/musketeers}}
View:
{
"musketeers": ["Athos", "Aramis", "Porthos", "D'Artagnan"]
}
Output:
Athos
Aramis
Porthos
D'Artagnan
var tpl = document.getElementById('simple').innerHTML,
view = {
items: ['Stackoverflow', 'StackExchange', 'Webmaster', 'Programmers']
};
document.getElementById('output').innerHTML = Mustache.to_html(tpl, view);
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.js"></script>
<script type="template" id="simple">
<h1>Array Values</h1>
<ul>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
</script>
<div id="output"></div>
Related
I am using the AngularJS UI Sortable directive and I am trying to pull the data from my view into my controller and update/stop the sorting on every click. I am creating a blank array and then attaching the $scope.areas to the blank array. I am able to display the content through the ng-repeat. However, when I console.log(areas), I am getting an undefined.
VIEW
<div class="panel-body">
<ul ui-sortable="sortableOptions" ng-model="areas" class="uk-nestable">
<li data-item="{{area.label}}" data-item-id="{{area.order}}" ng-repeat="area in areas">
<div class="uk-nestable-item mainarea-blue">
<div class="uk-nestable-handle mainarea-text-white"></div>
<div data-nestable-action="toggle"></div>
<div class="list-white">{{area.label}}</div>
</div>
</li>
</ul>
</div>
CONTROLLER
//create a blank array
var tmpList = [];
//attaches ng-model scope to tmpList
$scope.areas = tmpList;
console.log(areas);
//changed old sort to new sort
$scope.sortingLog = [];
$scope.sortableOptions = {
//creates a log entry of the new update view
update: function(e, ui) {
var logEntry = tmpList.map(function(i){
return i.value;
}).join(', ');
//displays the update text and array
$scope.sortingLog.push('Update: ' + logEntry);
},
stop: function(e, ui) {
// this callback has the changed model
var logEntry = tmpList.map(function(i){
return i.value;
}).join(', ');
$scope.sortingLog.push('Stop: ' + logEntry);
}
};
My goal is to display the area.label in the correct sort order. For example; I have 3 unordered lists - floor, basement, kitchen and I want to change the order to basement, floor, kitchen. As I am changing the sort order it is updating and stop the sorts.
I am probably not doing the best job explaining myself so here is a similar codepen...http://codepen.io/thgreasi/pen/jlkhr.
Had created and used my custom polymer element which is a table. Now, I want to use the check box element from their catalog in my table.
However, I keep getting this error when I reference the check box html file in my index page:
DuplicateDefinitionError: a type with name 'dom-module' is already
registered
This is how I have created my custom element:
<!-- Imports polymer -->
<link rel="import" href="polymer/polymer.html">
<script src="underscore-min.js"></script>
<!-- Defines element markup -->
<dom-module id="custom-table" >
<template>
<style>
ul {list-style-type:none; display:block}
ul li {display:inline; float:left; padding:20px; width:1.5em; border-bottom:1px solid #eee}
</style>
<h2>{{title}}</h2>
<table id="dataTable">
<thead id="tableHead"></thead>
<tbody id="tableBody"></tbody>
</table>
</template>
</dom-module>
<!-- Registers custom element -->
<script>
Polymer({
is: 'custom-table',
// Fires when an instance of the element is created
created: function() {
},
// Fires when the local DOM has been fully prepared
ready: function() {
var context= this;
this.pageNo=0;
this.totalPages=0;
// set the default paging size:
if(this.page== null|| this.page==undefined)
this.page=10;
// delegate the change selection handler to the table body
this.$.tableBody.addEventListener("click",function(e){
if(e.target && e.target.nodeName == "INPUT") ;
{
context.changeSelection(e.target);
}
});
},
// Fires when the element was inserted into the document
attached: function() {},
// Fires when the element was removed from the document
detached: function() {},
// Fires when an attribute was added, removed, or updated
attributeChanged: function(name, type) {
alert("changed");
},
loadData: function(columns,data){
this.data = data;
// add the selected property to the values
for(var i=0;i<this.data.length; i++) { this.data[i].Selected = false;}
this.filteredData=this.data;
this.columns = columns;
//initialize the filteredData
this.filteredData=data;
// calculate the total number of pages
this.totalPages= Math.ceil(data.length/this.page);
this.drawTableHeader();
_.defer(this.applyFilters,this);
_.defer(this.drawTableBody,this);
},
drawTableHeader:function(){
var columns = this.columns;
// load the header
var headTr = document.createElement('tr');
//add a blank header for the check box;
var th=document.createElement('th');
headTr.appendChild(th);
for(var i = 0; i<columns.length ;i++)
{
var td=document.createElement('th');
// if the column is sortable then add the event listener for sorting it
if(columns[i].Sortable)
{
td.addEventListener("click",function(){ this.sortBy(columns[i].Title); });
}
td.innerText = columns[i].Title;
headTr.appendChild(td);
}
this.$.tableHead.appendChild(headTr);
},
drawTableBody: function(context){
// this is a defered function
var context = context;
// get the number of items according to the current page number
var pageItems= context.filteredData.slice((context.page*context.pageNo),((context.page*context.pageNo)+context.page));
console.log(pageItems);
// print the page items
for(var i=0; i < pageItems.length; i++)
{
var currItem = pageItems[i];
var tr= document.createElement("tr");
// add the check box first
var checkbox= document.createElement("input");
checkbox.type="checkbox";
checkbox.checked=pageItems[i].Selected;
var ItemId = currItem.Id;
checkbox.setAttribute("data-ItemId",ItemId-1);
var td=document.createElement('td');
td.appendChild(checkbox);
tr.appendChild(td);
// for every column specified add a column to it
for(var j = 0; j< context.columns.length; j++)
{
var td=document.createElement("td");
td.innerText= pageItems[i][context.columns[j].Title];
tr.appendChild(td);
}
//append the row to the table;
context.$.tableBody.appendChild(tr);
} // end for i
},
applyFilters:function(context){
if(context.filter)
{
alert("filterApplied");
}
},
changeSelection:function(checkbox){
var ItemId = checkbox.getAttribute("data-ItemId");
this.data[ItemId].Selected= checkbox.checked;
console.log(this.data[ItemId]);
},
properties:{
title :String,
columns:Array,
data:Array,
page:Number,
filters:Object,
Selectable:Boolean
}
});
</script>
and here is what my index page looks like:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title><my-repo></title>
<!-- Imports polyfill -->
<script src="webcomponents-lite.min.js"></script>
<!-- Imports custom element -->
<link rel="import" href="my-element.html">
<link rel="import" href="bower_components/paper-checkbox/paper-checkbox.html">
</head>
<body unresolved>
<!-- Runs custom element -->
<custom-table title="This is data table"></custom-table>
<script>
document.addEventListener("WebComponentsReady",function(){
var data = [{'Id':1,'firstName':'aman',age:25},{'Id':2,'firstName':'gupta',age:25}];
var cols = [{Title:'firstName',Sortable:true},{Title:'age',Sortable:false}];
var a = document.querySelector('my-element');
a.loadData(cols,data);
});
</script>
</body>
</html>
I've just started out with polymer and I'm not quite sure what's going on here..
Thank you in advance :)
I got what the problem is..
My custom element was referencing a different Polymer.html file.
Silly me :D
I'm using Polymer Starter Kit Yeoman generator on Windows and I had the same problem:
Error: DuplicateDefinitionError: a type with name 'dom-module' is already registered
This error is triggered in Firefox console. Chrome works fine.
The components created with the generator (example: yo polymer:el my-element) have this polymer.html import:
<link rel="import" href="..\..\bower_components/polymer/polymer.html">
The base path is described with "backslash".
In some custom polymer elements I created by myself, I imported polymer.html with:
<link rel="import" href="../../bower_components/polymer/polymer.html">
And I think this lead to a duplication of some kind. To solve the problem, I just changed all automatically created imports, using only forward slashes /.
Hope this helps someone.
i tried to create dynamically changing dropdown list in angularJS
angulars.js
var option1Options = ["Class","Category","Option","Question","Group"];
var option2Options = [["Group","ProductModel"],
["Class","ProductModel"],
["Class","Group","ProductModel"],
["Group","ProductModel"],
["ProductModel"]];
$scope.myCtrl= function()
{
$scope.options1 = option1Options;
$scope.options2 = [];
$scope.getOptions2 = function(){
var key = $scope.options1.indexOf($scope.child);
$scope.options2 = option2Options[2];
};
}
page.html
<div id="CreateChild" ng-controller="myCtrl">
<select ng-model="child" ng-options="option for option in options1" ng-change="getOptions2()">
</select>
<select ng-model="parent" ng-options="option for option in options2">
</select>
</div>
in angulars.js i was unable to get the index of first dropdown list array. the value of key is assigned as -1 and the option2 is assigned as undefined.
can any one help me with this
I did a small workaround for this requirement, though it is not a straight answer, I believe this would help you...
Add this to your controller...
$scope.getOptions1Idx = function(){
var mySelectedOption = $scope.child;
var i = 0;
for(i=0;i< option1Options.length;i++){
if(option1Options[i]==mySelectedOption){
break;
}
}
return i;
}
and change your getOptions2 function as follows
$scope.getOptions2 = function(){
$scope.options2 = option2Options[getOptions1Idx()];
};
This can be done in much better fashion by avoiding for loop provided if you choose to change your array structure with predefined index some thing like var option1Options = [{id:0,option:"Class"},{id:1,option:"Category"},{id:2,option:"Option"},{id:3,option:"Question","Group"}];
Had a very similar problem with this. In terms of styling I found my way around it by creating a list instead of a select option
<div class='btn-group'>
<button class='form-control col-md-3' data-toggle='dropdown'>
{{value}} <span class='caret'></span>
</button>
<ul class='dropdown-menu'>
<li ng-repeat='type in callType' class='col-md-3'>
<a href='#' ng-click='select(type)'>{{type.name}}</a>
</li>
</ul>
</div>
Then the controller is used to take in the objects, call a method to change each object and then set a default for the drop down list. You can see it at the link below.
http://plnkr.co/edit/nwXmMif8vjj92pQmalb2
I am currently trying to make a 'show posts' button, for my Angular.js app. I am having trouble in setting the limitTo dynamically from an external script. So far I have:
<body ng-controller="FeedCtrl">
<h1>Feeds</h1>
<div ng-repeat="feed in (feedLoader = (feeds | limitTo:5))">
<p>{{feed.content}}</p>
</div>
<button ng-click="showPosts()">Show more...</button>
</body>
The approach I have taken is this:
$scope.showMorePosts = function () {
$scope.feedLoader = (feeds | limitTo:feedLimit);
}
...then replaced limitTo:5 with limitTo:feedLimit in the inline part of the view.
I have set up a Plunker with the basic setup so far here: http://plnkr.co/edit/OFqkGFKVUHKi2A20c4t3
Any help would be great!
Thanks,
JP
Seems like you were on the right track, but you just needed to define showPosts():
$scope.showMore = function() {
$scope.feedLimit += 1;
}
Full example:
http://plnkr.co/edit/pE49Wt0rvDjWhsKD0WiD?p=preview
HTML
<div ng-repeat="feed in (feedLoader = (feeds | limitTo:feedLimit))">
<p>{{feed.content}}</p>
</div>
<button ng-click="feedLimit = feedLimit + 1">Show more...</button>
JavaScript:
app.controller('FeedCtrl', function($scope) {
$scope.feedLimit = 3;
// ...
});
Using Ember.js I get an endless loop with the following code:
Controller:
App.activityDetailsController = Em.Object.create({
activityBinding : 'App.navController.selectedActivity',
data : function(){
var things = new Array();
if(this.activity){
var info = this.activity.get('info');
var len = info.length;
for(var i=0; i<len; i++){
for(prop in info[i]){
things.push({"key": prop, "value" : info[i][prop]});
}
}
}
return things;
}.property('activity')
})
View:
App.ActivityDetailsView = Em.View.extend({
templateName : 'activity-details',
activityBinding : 'App.activityDetailsController.activity',
dataBinding : 'App.activityDetailsController.data'
})
Template:
<script type="text/x-handlebars" data-template-name="activity-details">
<div id="info">
{{#each data}}
{{key}}: {{value}}<br />
{{/each}}
</div>
</script>
When trying to load this page, the 'data' function in the controller is called endlessly.
If I remove the {{#each}}{{/each}} block from the view, there is no problem and using {{data.length}} in the template gives the correct output.
Any ideas why this loops endlessly? If I remove 'activity' from the property call, it the problem is the same.
Thanks,
Make your "data" property cacheable(). See ebryn's answer to a related question for the reason why.