Meteor: Access reactive dict variable in child template - javascript

I need to check in a child template the value of a reactive dict variable, which was created in the parent template.
<template name="parent">
{{ > child }}
</template>
<template name="child">
{{#if something}}
checked
{{/if}}
</template>
This is how I initialize a reactive dict variable to the parent template:
Template.parent.onCreated(function() {
this.blabla = new ReactiveDict();
});
So for the parent template this helper is working:
Template.parent.helpers({
anything: function(type) { return (Template.instance().blabla.get('foo') === 'bar') ? true : false; }
});
But it won't work for the child:
Template.child.helpers({
something: function() { return (Template.instance().blabla.get('foo') === 'bar') ? true : false; }
});
So how can I check the value of the variable in the child helper?

At its core, this question is about how to find a template's parent instance. I'd recommend reading all of the answers here.
I'll build on the idea presented by Sacha, with this example:
html
<template name="parent">
{{ > child parentHelper=parentHelper}}
</template>
<template name="child">
{{#if parentHelper}}
<h1>pass</h1>
{{else}}
<h1>fail</h1>
{{/if}}
</template>
js
Template.parent.onCreated(function() {
this.dict = new ReactiveDict();
this.dict.set('foo', 'bar');
});
Template.parent.helpers({
parentHelper: function() {
return Template.instance().dict.equals('foo', 'bar');
}
});
If that exact pattern doesn't work in your code, you can try one of the others from the linked question above.

Related

Vue.js $ref not found

I am trying to dynamically set the padding of an element using inline styles, based on the height of the parent. For this I am using:
<div class="stock-rating positive" ref="stockRating">
<div class="stock-rating-start-end" v-bind:style="{ paddingTop: paddingTop }">
<div>{{ rating.value_start }}</div>
<div>to</div>
<div>{{ rating.value_end }}</div>
</div>
</div>
paddingTop will be a computed property. However, before I compute it, I have to actually access the $ref of the parent element (stockRating). But, it is not found in the computed property, even though the $refs object looks to contain it.
paddingTop : function(){
console.log(this.$refs);
console.log(this.$refs.stockRating);
/*computation here*/
}
The console.log output is:
Why is this.$refs.stockRating undefined if this.$refs has the stockRating property, and I see it contains the correct elements as well? How do I resolve this?
You have to tell vue that DOM is ready and component was mounted.
new Vue({
el: "#app",
computed: {
itemRef() {
console.log(this.$refs.item)
return this.ready ? this.$refs.item : false
}
},
data: () => {
return {
ready: false
};
},
mounted() {
this.ready = true;
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id='app'>
<div ref="item" class="item">
{{itemRef}}
</div>
</div>
Well your $refs.stockRating is defined AND exists but it will not exists until the component is mounted as explained here.
I didn't try it but I guess that if you try to console.log your $refs.stockRatinginside the mounted(){} component property it should not be empty

Accessing an element inside a Vuejs component

I'm trying to access an element from the dom from within my Vue component but I just get 'null'. If I go into dev tools and try I can access it. I'm assuming it's a scoping issue but I can't find the answer.
<template>
<ul class="list-group" id="criteria" v-for="item in criteria">
<li class="list-group-item">{{ item.name }}</li>
</ul>
</template>
<script>
export default {
template: "report-criteria",
data() {
return {
criteria: []
}
},
ready() {
console.log(document.getElementById('criteria'));
},
methods: {},
};
</script>
The answer posted by #nils is for VueJS 1.x. The v-el directive was removed in newer versions. It was replaced by ref attribute.
To achieve that same result in VueJS 2.x, you should do the following instead:
<template>
<ul class="list-group" id="criteria" ref="criteria" v-for="item in criteria">
<li class="list-group-item">{{ item.name }}</li>
</ul>
</template>
<script>
export default {
data() {
return {
criteria: []
}
},
mounted() {
console.log(this.$refs.criteria);
},
methods: {},
};
</script>
You may find more info about that change in VueJS docs.
VueJS 1.x
You're probably easier off using the v-el directive, which allows you to map elements in your component to an vm property on this.$els.
Also, AFAIK, you shouldn't combine the template property with templates in the .vue file (assuming you are using .vue files, of course).
<template>
<ul class="list-group" id="criteria" v-el:criteria v-for="item in criteria">
<li class="list-group-item">{{ item.name }}</li>
</ul>
</template>
<script>
export default {
data() {
return {
criteria: []
}
},
ready() {
console.log(this.$els.criteria);
},
methods: {},
};
</script>
Here are the steps that worked for me:
Reference your $ref in the html element:
<p ref = "myref">Welcome to myApp</p>
Define a boolean variable in the script:
shown = false
In the update life cycle hook, keep this code:
update(){
if(this.shown){
console.log(this.$refs.myref)
your code
}
}
Change the boolean to "true" inside your function like the below code:
test(){
this.shown = false
....
some code
....
this.shown = true // this will trigger the code written in the update hook
}

Meteor: Using variable in child template

I'm using template-level subscriptions, but I have some problems to use the results in a child template:
As I'm loading the template example, the template exampleChild will be displayed (just take this as an basic example - I know this doesn't make sense right now).
On creating the main template, the subscription is done and the data gets stored in a helper:
Template
<template name="example">
{{> Template.dynamic template=switch}}
</template>
<template name="exampleChild">
<h1>{{result}}</h1>
</template>
Helper
Template.example.helpers({
switch: function() { return 'exampleChild'; },
result: function() { return Template.instance().result(); },
});
Event
Template.example.onCreated(function() {
var instance = this;
instance.autorun(function () {
var subscription = instance.subscribe('posts');
});
instance.result = function() {
return Collection.findOne({ _id: Session.get('id') });
}
});
If I would put the {{result}} in the example-Template, everything is working. But I need to use the variable in the child template.
Did you try:
<template name="example">
{{#with result}}
{{> Template.dynamic template=switch}}
{{/with}}
</template>
<template name="exampleChild">
<h1>{{this}}</h1>
</template>
With doc
When doing that, I prefer wrap the data context result into an object, to have something proper on the child like:
Template.example.helpers({
switch: function() { return 'exampleChild'; },
data: function() { return {result: Template.instance().result()} },
});
<template name="example">
{{#with data}}
{{> Template.dynamic template=switch}}
{{/with}}
</template>
<template name="exampleChild">
<h1>{{result}}</h1>
</template>
Hope it's help
You could store the result in a session variable, and then add another helper to exampleChild that waits for the session variable.

EmberJS: Insert component dynamically

Got following components:
App.ParentComponent = Ember.Component.extend({
child: '',
yieldTemplateName: 'empty_by_default',
setup: function(){
//append here child compoment
}.on('didInsertElement')
});
App.ChildComponent = Ember.Component.extend({
templateName: 'some_location',
actions:{
//whatever
}
});
What am I wondering if is possible to add child component into parent's at any render status and based on a parameter?
So I call, for example:
{{parent child="child"}}
And it eventually renders:
<div !-- parent -- >
<div !-- child -- > </div>
</div>
App.ParentComponent = Ember.Component.extend({
child: null,
hasChild: Em.computed.notEmpty('child')
});
// parent template
{{#if hasChild}}
{{component child}}
{{/if}}
// another template
{{parent child="child"}} {{!-- displays ChildComponent --}}
Note: The component helper will be available in Ember 1.11. If you are using an earlier version, you can use the ember-dynamic-component addon.

How to access another collection by ID in Meteor template?

Let's say I have a Posts collection, the data for which looks like this:
var post1 = {
title: "First post",
post: "Post content",
comments: [<comment id>, <another comment id>, <etc>]
};
And I have a corresponding Comments collection. I've published and subscribed to both collections and want to display a post with it's comments.
How do I go about displaying the comments for that specific post?
<template name="post">
<h1>{{title}}</h1>
<p>{{post}}</p>
{{#each comments}}
// Only have access to the ID
{{/each}}
</template>
I could create a helper like this:
Template.post.helpers({
displayComment: function(id) {
return Comments.findOne(id).fetch().comment;
}
});
and do:
<template name="post">
<h1>{{title}}</h1>
<p>{{post}}</p>
{{#each comments}}
{{displayComment #index}}
{{/each}}
</template>
But then I'd have to create a helper for each of the comment object's properties, etc.
What's the clean way to do it? I don't want to populate the comments field on the post object, since that would mean calling .fetch(), and posts would no longer be reactive.
A couple of suggestions:
<template name="post">
<h1>{{title}}</h1>
<p>{{post}}</p>
{{#each comments}}
{{#with commentDetails}}
{{userName}} //
{{content}} // These are properties of a comment document
{{upvotes}} //
{{/with}}
{{/each}}
</template>
Template.post.helpers({
commentDetails: function() {
return Comments.findOne(this);
}
});
That will set the data context within each with block to be the comment object returned by looking up the current _id (which is the value of this in the commentDetails helper within the each block).
An alternative would be to just use an each block on its own, but have it iterate over a cursor:
<template name="post">
<h1>{{title}}</h1>
<p>{{post}}</p>
{{#each commentCursor}}
{{content}}
... // other properties
{{/each}}
</template>
Template.post.helpers({
commentCursor: function() {
return Comments.find({_id: {$in: this.comments}});
}
});

Categories