Meteor data context, passing array into each Spacebars loop - javascript

In this Example 2 -- "Passing a data context"
JS
Template.overview.helpers({
users: [
{ name: 'David' },
{ name: 'Shaune' }
]
});
HTML
<template name="overview">
{{> userList users}}
</template>
<template name="userList">
{{#each this}}
{{name}}<br>
{{/each}}
</template>
Result
David
Shaune
My goal is to pass an array of template names into Template.overview where users is, like so:
<template name="overview">
{{#each templateArray }}
{{> userList this }}
{{/each}}
</template>
Where templateArray is an array of strings with template names, and this is the name of each template.
Is this possible?
EDIT:
For more depth, consider that I have the following in my helpers
Template.overview.helpers({
users: [
{ name: 'David' },
{ name: 'Shaune' }
],
otherUsers: [
{ name: 'Jane' },
{ name: 'Betty' }
],
moarUsers: [
{ name: 'Ben' },
{ name: 'Jerry' }
]
});
And I'd like to pass each of these data context into the same template (in this case userLists).

You don't need to call anything, you can use this inside helper, like
helper: function(){
return this; //if you pass string via templateArray
return this.name; //if you pass object via templateArray
}
Because what you do looks like this but is just wrapped nicely into templates
<template name="overview">
{{#each templateArray }}
{{name}}<br>
{{/each}}
</template>
I don't know why you have in code double loop, in first loop you pass object and it can't iterate throught it
EDIT
If you wanna just loop throught array of strings, do:
{{#each templateArray}}
{{this}}<br>
{{/each}}

Related

How to Store Data Property Value from a Specific Item in Rendered List in Vue

I'm trying create a follow button on list items in Vue. My strategy is to grab the value of a particular list item property and store it in the data object. Then use this value in a method to add it to an array in my database.
<div v-for="result in results" :key="result.symbol">
{{ result.name }}
<button #click="followStock">+follow</button>
</div>
I'm not sure how to get the value of result.symbol "into" the button element to set the value symbol in the data object below.
<script>
export default {
data() {
return {
results: [ // this is populated by an api call
{
currency: "USD"
exchangeShortName: "NYSE"
name: "International Game Technology PLC"
stockExchange: "NYSE"
symbol: "IGT"
},
{...},
...
],
symbol: "",
};
},
followStock() {
// add this.symbol to database array
},
},
};
</script>
I'm guessing there might be an easier strategy I'm overlooking as I'm still new to Vue, so any other solution that essentially allows me to fire off the value of result.symbol from any rendered result to my database would be awesome.
You can just pass the result as a parameter to your method.
<div v-for="result in results" :key="result.symbol">
{{ result.name }}
<button #click="followStock(result)">+follow</button>
</div>
And in your method:
methods: {
followStock(result) {
// do something with result
console.log({result});
let symbol = result.symbol;
},
}
P.S I didn't see you put your followStock() inside a methods object, but I did so in the example. https://v2.vuejs.org/v2/api/#methods
Write directly as a function call.
The vue compiler will turn followStock(result.symbol) into function(event) {followStock(result.symbol)}.
new Vue({
el: '#app',
data() {
return {
results: [
{
name: "International Game Technology PLC",
symbol: "IGT"
},
{
name: "A name",
symbol: "A symbol"
}
]
};
},
methods: {
followStock(symbol) {
console.log(symbol)
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="result in results" :key="result.symbol">
{{ result.name }}
<button #click="followStock(result.symbol)">+follow</button>
</div>
</div>
As Nazaire mentioned you can access the results anywhere inside the child elements when using v-for.
(it works like a normal for-loop)
It's not only limited to the corresponding element (the element in which you do v-for)
<div v-for="result in results" :key="result.symbol">
{{ result.name }}
<button #click="followStock(result.symbol)">+follow</button>
</div>
followStock(symbol){
// you can now add symbol to db
}

Meteor.user custom field displaying a single list of items in one html tag instead of each item in its own tag

I have a custom user field that get populated by the user on click of a button with an id of an item from another collection, however when i return it, i get a single list of the items in one html tag, instead of returning each saved item in its own tag with the result looking like this
i.e its like this
<p>CategoryPublication-98,CategoryPublication-2,CategoryPublication-57<p>
when it should be like this
<p>CategoryPublication-98</p>
<p>CategoryPublication-2</p>
<p>CategoryPublication-57</p>
this is my publish
Meteor.publish(null, function() {
return Meteor.users.find({_id:{$in:fields.name}}).fetch();
});
my html
<template name="userTimeline">
{{#if currentUser}}
<div class="timeline-user">
{{#each name}}
<p>{{name}}</p>
{{/each}}
</div>
{{/if}}
</template>
my helper
Template.userTimeline.helpers({
name: function() {
return Meteor.user().name;
}
});
my insert
Template.CategoriesMain.events({
'click .toggle-category': function(e){
var ob = this._id;
var id = $.makeArray( ob );
console.log(id);
e.preventDefault();
Meteor.call('addingCategory', id, function(error, user){ console.log(id)});
},
});
My methods
Meteor.methods({
addingCategory: function(name) {
console.log(Meteor.userId());
Meteor.users.update({
_id: Meteor.userId()
},
{
$addToSet: {
name: name
}
});
}
});
Where you have:
{{#each name}}
<p>{{name}}</p>
{{/each}}
There's ambiguity about the value of name in the inner <p></p>. Since you're just returning an array of strings instead of objects there is no name key in the array.
Instead do:
{{#each name}}
<p>{{this}}</p>
{{/each}}

Meteor Templates helpers and access to collections' fields [duplicate]

This question already has answers here:
How do I check if an array includes a value in JavaScript?
(60 answers)
Closed 7 years ago.
I have two collections:
Group = {
users: [Array_of_User]
}
User = {
name: _string_
}
I'm listing groups ans I'm trying to know in the template if a user is in the groups:
mytemplate.js
Template.mytemplate.helpers({
groups: function(){
return Groups.find();
},
currentUsername: 'test'
});
mytemplate.html
<template name="main">
<ul>
{{#each groups}}
<li>
{{#if [the group contains currentUsername] }}
contains
{{else}}
doesn't contain
{{/if}}
</li>
{{/each}}
</ul>
</template>
The question is: what can I put on the helpers and instead of [the group contains currentUsername] to make it work?
Also, I'm not saying this is the way to do it. I'm open to any suggestions even if it means I have to change a lot.
You could use the Underscore.js function _.findWhere(list, properties) to check whether the group contains the username:
if (Meteor.isClient) {
Template.main.helpers({
groups: function() {
return Groups.find();
},
currentUsername: 'Matthias',
isInGroup: function(username) {
return !!_.findWhere(this.users, {
name: username
});
}
});
}
<template name="main">
<ul>
{{#each groups}}
<li>
{{#if isInGroup currentUsername}}
contains
{{else}}
doesn't contain
{{/if}}
</li>
{{/each}}
</ul>
</template>
if (Meteor.isServer) {
Meteor.startup(function() {
Groups.insert({
users: [{
name: "Matthias"
}, {
name: "Angie"
}]
});
});
}
Here is a MeteorPad.
Within your each block, your data context becomes the current group that is being iterated over. Therefore you can write a helper method that references that current data context like this:
userInGroup: function(username) {
var userInGroup;
this.forEach(function(groupUsername) {
if (username == groupUsername) {
userInGroup = true;
}
};
return userInGroup;
}
'this' within the userInGroup template helper references the current group as long as you use the helper within an a group iteration.
You can then use the helper like this:
<template name="main">
<ul>
{{#each groups}}
<li>
{{#if userInGroup currentUsername}}
contains
{{else}}
doesn't contain
{{/if}}
</li>
{{/each}}
</ul>
</template>

How iterate through two array in a object using Template helpers in Meteor.js

My HTML resembles this
<template name="stop">
{{#each thumb}}
<tr>
<td class="image" ><img src="{{this.data}}"></td>
<td>
<center style="float:right; margin-bottom: 25%;">
<h2> Do you like this product? </h2>
<h2>{{this.text}}</h2></center>
</td>
</tr>
{{/each}}
</template>
And this template refers to my template helper which look like this
Template.stop.helpers( {
'thumb': function(data) {
console.log(z);
return tweetImages.findOne()
})
tweetImage.findOne() outputs this
Object {_id: "1", data: Array[7], text: Array[7]}
I'm trying to iterate through each item in both of the arrays for each time the template run but instead all the 7 values for each array get outputted each time. I know the contextual variable this is need somewhere but I cannot work it out. Would anyone have any ideas?
findOne returns only one element so your each only iterates one time.
You need a nested each to go through the data or text property like this:
{{#each thumb}}
...
{{#each data}}
//but you won't be able to get 'text' here
{{/each}}
...
{{/each}}
But as you can see you won't be able to access both data and text arrays with this method. Maybe you could modify the data returned by your helper so it has the following form:
[
{data: ..., text: ...},
{data: ..., text: ...},
{data: ..., text: ...},
...
]
So you could do:
{{#each thumb}}
...
{{data}}
{{text}}
...
{{/each}}
To rewrite your data you could use a for loop:
Template.stop.helpers({
'thumb': function() {
var result = tweetImages.findOne();
var newResult = [];
for(var i = 0; i < result.data.length; i++) {
newResult[i] = {data:result.data[i], text:result.text[i]};
}
return newResult;
}
});

Handlebars.js using ../ to reference parent Context

Lets say I have the following JSON and handlebars.js template :
JSON
{
rootPath: '/some/path/',
items:[ {
title: 'Hello World',
href: 'hello-world'
}, {
title: 'About',
href: 'about'
}, {
title: 'Latest News',
href: 'latest-news'
}
}
Template
<script id="test-template" type="text/x-handlebars-template">
<ul class="nav">
{{#each items}}
<li>{{title}}</li>
{{/each}}
</ul>
</script>
The template above works, until I want to filter items - lets say to have 2 lists one odd and the other even, here's a simple template for odd :
<script id="test-template" type="text/x-handlebars-template">
<ul class="nav">
{{#each items}}
{{#isOdd #index}}
<li>{{title}}</li>
{{/isOdd}}
{{/each}}
</ul>
</script>
And the registered helper :
// isOdd, helper to identify Odd items
Handlebars.registerHelper('isOdd', function (rawValue, options) {
if (+rawValue % 2) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
The helpers work as expected and only the Odd items are rendered, however the reference to the parent context becomes lost, so the {{../rootPath}} directive ~~fails to render~~ renders an empty value.
Is there a way to pass the Parent context through the block Helper?
Change this:
<a href="{{../rootPath}}{{href}}">
to this:
<a href="{{../../rootPath}}{{href}}">
Why? because the if statement is in an inner context so first you need to go up a level and that's why you have to add ../
See more details in:
https://github.com/wycats/handlebars.js/issues/196

Categories

Resources