Mustache (or Handlebars) iterating over two lists - javascript

I have two arrays:
var content = {
"girls": ["Maria", "Angela", "Bianca"],
"digits": ["21.143.191.2", "123.456.78.90", "971.6.17.18.1"]
};
and a template:
<script id="template" type="text/template">
<ul>
<li>{{girls}}</li>
</ul>
</script>
I'd like the end result to be:
<ul>
<li>Maria</li>
<li>Angela</li>
<li>Bianca</li>
</ul>
I've tried block mustaches like {{#girls}} {{.}} {{/girls}} and {{#digits}} {{.}} {{/digits}} but no matter which way I nest them I seem to get repeats instead of interlacing.
Any Ideas?
PS: Obviously in the future we'll be asking for IP addresses, not phone numbers.
PPS: None of those are intended to be real IPs, please don't try to contact those girls!

You need to rearrange your content so that you can iterate over just one thing. If you combine those two arrays with something like this:
var data = { girls: [ ] };
for(var i = 0; i < content.girls.length; ++i)
data.girls.push({
name: content.girls[i],
number: content.digits[i]
});
Then a template like this:
<script id="template" type="text/template">
<ul>
{{#girls}}
<li>{{name}}</li>
{{/girls}}
</ul>
</script>
should work.

With "mu is too short"'s advice. And a few crazy ideas I came up with an interesting approach to complex templating. *It almost works!
So let's say I have this content (or data or view) which I want to put into a template:
var content = {
title: "Black Book",
girls: ["blonde", "brunette", "redhead"],
digits: ['123', '456', '789'],
calc: function () {
return 2 + 4;
}
};
And I have a template like this:
<script type="text/template" id="template">
<h1>{{title}}</h1>
<h3>{{calc}}</h3>
<ul>
<li>{{hair}}</li>
</ul>
</script>
And the end result I want is this:
<h1>Black Book</h1>
<h3>6</h3>
<ul>
<li>blonde</li>
<li>brunette</li>
<li>redhead</li>
</ul>
The problem we'll encounter is that we have arrays (or lists) nested in our original content, and if we tried to Mustache.render(html, content) we'd end up with only one li item or a whole array within one href="" attribute. So sad...
So he's the approach, pass through the template multiple times. The first time, pass through and replace the top level items, and adjust the template for the next pass through. The second time, adjust one of the lists, and adjust the template for the third pass through, etc for how ever many layers of content you have. Here's the new starting template:
<script type="text/template" id="template">
<h1>{{title}}</h1>
<h3>{{calc}}</h3>
<ul>
{{#hair}}
{{#digits}}
<li>{{hair}}</li>
{{/digits}}
{{/hair}}
</ul>
</script>
On the first pass through fill in the top level stuff, and change {{digits}} to {{.}}
$.each(content, function (index, value) {
template2 = template.replace(/{{title}}/ig, content.title)
.replace(/{{calc}}/ig, content.calc)
.replace(/{{digits}}/ig, '{{.}}');
});
Now you have this:
<h1>Black Book</h1>
<h3>6</h3>
<ul>
{{#hair}}
{{#digits}}
<li>{{hair}}</li>
{{/digits}}
{{/hair}}
</ul>
On the next pass through we'll just call Mustache.render(template2, content.digits); and that should give us:
<h1>Black Book</h1>
<h3>6</h3>
<ul>
{{#hair}}
<li>{{hair}}</li>
<li>{{hair}}</li>
<li>{{hair}}</li>
{{/hair}}
</ul>
And that's where my logic dies, haha. Any help thinking this through would rock! I'm thinking I could take out the {{hair}} block elements and just do a $.each pass through content.girls and stack .replace three times. Or I could try to start with lowest level of content, and work my way up. I dunno.
All this basically leaves me wondering if there's some "logic-less" way for this kind of nesting or multiple pass throughs to be put into mustache does handlebars do it?

Related

How do I remove duplicate values ​in a v-for array?

I coded like this to remove duplicate values.
vue
<div class="col-md-6" style="float: left">
<ul class="list-group">
<li class="list-group-item"
:class="{ active: index1 == currentIndex1 }"
v-for="(member, index1) in uniqueMemName"
v-bind:value="member.mem_name"
:key="index1"
#click="setActiveMember(member, index1)"
>
<strong style="margin-bottom: 5px"> {{member.mem_name}} </strong>
</li>
</ul>
</div>
vue (script)
computed: {
uniqueMemName() {
return _.uniqBy(this.members, function(m) {
return m.mem_name;
});
}
},
I also installed lodash. But I get an error. Which part is wrong?
Please let me know if there is another method other than the one I wrote.
++) error console
console window
++) array information:
I have tables A and B. Table A imports only the mem_name column. Table B imports all columns.
Example ->
a.mem_name
b.col1
b.col2
mem1
10
20
mem1
30
40
mem2
50
60
I'm working on making duplicate mem_names into one at this time. Using lodash's unique features.
If you want to use lodash just for this, which sounds like the case, I suggest that there may be a better way without it, only using newer vanilla JS:
...
computed: {
uniqueMemName() {
return [...new Set(this.members.map(m => m.mem_name))]
}
}
Sets are always unique, so mapping and converting to a set and then back to array gives us a unique array.

access multiple instance of JSON keys/arrays values to HTML

My first one/instance outputs fine.. However, if there is multiple found from 'ZipSearch' variable (which is the JSON header i.e. in my JSON code below, parrent 23222 value), "23222":[ ...
Below is a recent attempt at using [2] have also tried [1] etc. Any ideas on how to output the content of the following JSON datas with common Key value? Into my HTML page?
$('span.zip').html(myjson[ZipSearch][0].Zipcode);
$('span.state').html(myjson[ZipSearch][0]["Primary State"]);
$('span.city').html(myjson[ZipSearch][0].City);
$('span.countyS').html(myjson[ZipSearch][0]["County S"]);
$('span.county').html(myjson[ZipSearch][0].County);
$('span.zip1').html(myjson[ZipSearch][2].Zipcode);
$('span.state1').html(myjson[ZipSearch][2]["Primary State"]);
$('span.city1').html(myjson[ZipSearch][2].City);
$('span.countyS1').html(myjson[ZipSearch][2]["County S"]);
$('span.county1').html(myjson[ZipSearch][2].County);
Here's my JSON.
"23222":[ # sometimes has multiple responses per, ie below
{"Zipcode":"23222","City":"","Primary State":"Virginia","County S":"555","County":"Sample City"},
{"Zipcode":"23222","City":"","Primary State":"Utah","County S":"444","County":"Sample Bigger City"}
],
Basically, I'm unable to output the second line above, Utah etc, in my HTML page...... Just always repeating the content from the first.
This is the mark-up: (I am just trying to handle the content if there is multiple common arrays)
<li class="zip">Zip Code: <span class="zip"></span></li>
<li class="state">Primary State: <span class="state"></span></li>
<li class="city">City: <span class="city"></span></li>
<li class="countySSA">County SSA: <span class="countyS"></span></li>
<li class="county">County: <span class="county"></span></li>
<li class="zip1">Zip Code: <span class="zip1"></span></li>
<li class="state1">Primary State: <span class="state1"></span></li>
<li class="city1">City: <span class="city1"></span></li>
<li class="countySSA1">County SSA: <span class="countyS1"></span></li>
<li class="county1">County: <span class="county1"></span></li>
Update:
So, I have just tried this, below per answer - and still it just prints one set of arrays values to HTML.
myjson[ZipSearch].forEach(function(innerobj,index){
$('span.zip'+index).html(innerobj["Zipcode"]);
$('span.county'+index).html(innerobj["County"]);
$('span.county1'+index).html(innerobj["County"]);
})
if your object is
var obj=[
{"Zipcode":"23222","City":"","Primary State":"Virginia","County S":"555","County":"Sample City"},
{"Zipcode":"23222","City":"","Primary State":"Utah","County S":"444","County":"Sample Bigger City"}
]
use for each to access multiple object
obj.forEach(function(innerobj,index){
$('span.zip'+index).html(innerobj["Zipcode"]);
})

Angular recursive ng-include while keeping track of recursion depth

I have a situation that is pretty similar to this answer to the question here:
AngularJS ng-include with nested hierarchy
I have some data in the format
$scope.data = {
text: "blah",
comments:
[
{
text: ["blahL11", "blahL12", "blahL13"],
comments: [
{
text: ["blahL111", "blahL112", "blahL113"]
},
{
text: ["blahR111", "blahR112", "blahR113"]
}
]
},
{
text: ["blahR11", "blahR12", "blahR13"]
}
]
};
And I am display it with a recursive ng-include like this:
<ul>
<li>{{data.text}}</li>
<li ng-repeat="item in data.comments" ng-include="'tree'"></li>
</ul>
<script type="text/ng-template" id="tree">
<ul>
<li ng-repeat="text in item.text">{{text}}</li>
<li ng-repeat="item in item.comments" ng-include="'tree'"></li>
</ul>
</script>
http://plnkr.co/edit/8swLos2V6QRz6ct6GDGb?p=info
However, I would like to somehow keep track of the depth of the recursion as well. So that instead of simply displaying:
-blah
-blahL11
-blahL12
-blahL13
-blahL111
It could display
-1. blah
-2. blahL11
-2. blahL12
-2. blahL13
-3. blahL111
Without me modifying the data structure (as the depth is only really for display?). Can I insert a variable into the ng-include, is there some sort of recursive $index I can use?
You can do this using ng-init. This will assign a value to the new scope when it's created, which you can do by refering to a value in the old scope and incrementing it.
plnkr demo
<li ng-repeat="item in item.comments" ng-include="'tree'" ng-init="depth = depth + 1"></li>

How to use a variable in Angular filter

I am busty with experimenting with Angular. I get some data from controller and like to place a filter on it. This works as i pass is as string. but if i like to use a variable, it doesnt work. The variable is showing if i directly call it in the html. I will paste html and js here. I am sure i am doing something "small" wrong here, but i dont see what.
index.html
<body ng-controller="GuestController as GuestCtrl">
<h1 class="text-center">Guests</h1>
<div class="btn btn-default" ng-controller="FamController as famCtrl" ng-repeat="guest in GuestCtrl.guests | filter:{name:famCtrl.fam}">
<h3>
{{famCtrl.fam}} <!-- returns the right value, thats the az you see before the names -->
{{guest.name}}
</h3>
<ul class="clearfix" ng-controller="FamController as famCtrl">
<li class="small-image pull-left thumbnail" ng-repeat="famMember in guest.famMembers">
{{famMember}}
</li>
</ul>
</div>
</body>
app.js
var app = angular.module("wedding", []);
app.controller('GuestController', function(){
this.guests = guests;
});
app.controller('FamController', function(){
this.fam = 'az';
});
var guests = [
{
name: 'Willem & Hanneke',
famMembers: [
"Willem",
"Hanneke"
]
},{
name: 'Azouz & Ria',
famMembers: [
"Azouz",
"Ria",
"Ghalil"
]
}]
Any help would be appreciated. Probably there is a much better way to achieve what i like, but i like to do it in steps. My goal now is to get this working. The next goal would be to only display the fammember of the "name" i have clicked.
Extract your FamController outside of the ng-repeat directive
working example http://codepen.io/anon/pen/rbEoc?editors=101
<body ng-controller="GuestController as GuestCtrl">
<div ng-controller="FamController as famCtrl">
...
</div>
</body>

HTML structure in treeview with jQuery

I need to display a HTML structure in a treeview. I found some jQuery treeview plugins but they generally require a list.
Let's take a simple HTML (nodes may have different tags, not only 'div'):
<div id="node1">
<div id="node2">
<div id="node3"></div>
<div id="node4"></div>
</div>
<div>
I want to display it like this:
node1
node2
node3
node4
For now, i'm using this jQuery plugin: treeview
So I need to convert the HTML to an unordered list like this:
<ul>
<li>node1
<ul>
<li>node2
<ul>
<li>node3</li>
<li>node4</li>
</ul>
</li>
</ul>
</li>
</ul>
How can I do this using jQuery? If you think a different approach would be better, please let me know.
Here you go...that was fun. Demo - Updated to not be specific to div tags, and return an element, that could be turned into a html string.
$.fn.convertToUL = function(isTop) {
if(isTop==null) isTop=true;
var ul=$("<ul>");
var li=$("<li>");
li.append($(this).attr("id"));
var children=0;
$(this).children().each(function(){
ul.append($(this).convertToUL(false));
children++;
});
if(children>0)
li.append(ul);
if(li.is(':empty'))
return "";
if(isTop)
return $("<ul>").append(li);
return li;
}
//to get text of elements use .wrap('<div/>').parent().html()
var ulElement=$("#node1").convertToUL();
alert(ulElement.wrap('<div/>').parent().html());
$("#node1").replaceWith(ulElement);

Categories

Resources