Meteor Blaze Data Context becomes undefined - meteor

I have a blaze template like this:
{{>jobsheetsTable companyId=companyId}}
In the JS for the template I have the onCreated function like this ...
Template.jobsheetsTable.onCreated(function(){
const instance = this;
instance.companyId = new ReactiveVar();
console.log(instance, instance.data, instance.data.companyId);
if(instance.data.companyId){
instance.companyId.set(instance.data.companyId);
}
}
The issue is that in the console.log statement I notice something odd ...
instance is correctly outputting the instance with the data object and a companyId
instance.data however returns {companyId: undefined}.
I am not changing instance.data anywhere and the function being passed into this template does not change the companyId.
Update: Using meteor 1.6.1.

The onCreated callback is only run once per template creation, so the data you get is the one that is provided to the initial creation (likely with you attribute set to undefined).
It is likely that the data context is changed after the initial rendering, and this does not trigger the function. as the template is not re-created.
If you are certain that you want to track the data context in the onCreated callback, you need to set a reactive dependency on it, using the Template.currentData() reactive data source. Since it needs to be inside a reactive context in order to be re-run when the data changes, you will need to create one, and a convenient method of doing so is via this.autorun(), which stops the computation for you when the template is destroyed.
Template.jobsheetsTable.onCreated(function(){
this.companyId = new ReactiveVar();
this.autorun(() => { // creates a reactive computation
const data = Template.currentData(); // creates a reactive dependency
console.log('data context', data);
if(data.companyId){
this.companyId.set(data.companyId);
}
})
});
The code above contains an autorun block that will re-run whenever the data context changes.

Related

SvelteKit load function error: must return a plain object at the top level

I cannot get SvelteKit load function works when using it with Firebase, I always get this error message:
a load function related to route '/' returned a function, but must return a plain object at the top level (i.e. return {...})
I'm using onSnapshot here with Firestone to get the updated data whenever it changed on the database.
export function load() {
const queryParams = [orderBy('date')];
const q = query(collection(db, 'daily_status'), ...queryParams);
messagesUnsubscribeCallback = onSnapshot(
q,
querySnapshot => {
let data = querySnapshot.docs.map( doc => (
JSON.parse(JSON.stringify(
{
id: doc.id,
status: doc.data().status,
date: doc.data().date.toDate().toLocaleDateString('en-au'),
note: doc.data().note
}
))
))
return { daily_status: data }
})
return messagesUnsubscribeCallback;
}
It looks like your issue is the fact that you are returning the function onSnapshot() inside the load function. The only thing you can return inside a load method is a plain object as the error states. What you might want to do is to run the snapshot code inside an onMount.
Another solution would be creating a svelte store and pass the onSnapshot into the store. An example can be seen in this tutorial:
https://www.captaincodeman.com/lazy-loading-and-querying-firestore-with-sveltekit#introduction
Reference:
https://kit.svelte.dev/docs/load
Your load() function needs to run asynchronous code, so it can't return back the data directly. Instead, you need to change it to return a promise that resolves to the loaded data. For an example using fetch(), see:
https://kit.svelte.dev/docs/load#making-fetch-requests
In your case, you need to create your own promise.
Further more, the purpose of the load() function is to load the initial data the page needs to be able to render. As suggested by another, to subscribe to updates in the future, do that in the page component in onMount(), so you only subscribe to future updates when the component is rendered in the web browser.

Meteor: How to access Template's Instance key in Blaze directly (without helper)?

Template.Demo.onCreated(function() {
this.test = 'Text';
});
How to access that template's instance test key in Blaze directly (without creating a helper function)?
{{Template.instance.test}} seems not to work (it was suggested here).
I don't believe this is possible with current versions of Blaze. That being said, you can simulate this by declaring a single global Template helper function, like:
Template.registerHelper('instance', function () {
return Template.instance();
});
Just define this once in a common client location, and you can then reference instance in any of your Template's. So you could reference your test variable like:
{{instance.test}}

meteor and reactJS - how to make child components reactive?

I have a child component that depends on another widget to set what data it should subscribe to. So effectively a dynamic subscription.
getMeteorData() {
var topicName = this.context.topicName;
var handle = Meteor.subscribe('RebotTopicDetail', {name: topicName});
...
If topicName changes I want to re-subscribe to new data.
What is the best way to do this?
The topicName is being set by another component, and I am using context to pass it between objects.
https://facebook.github.io/react/docs/context.html
I can see the context.topicName is changing as I am displaying it.
But it's not triggering the reactive calculation inside meteor data to rerun.
Is there a way to declare a Deps on a variable within getMeteorData?
My understanding was that was a reactive block so changes would cause the getMeteorData block to re-run.
https://react-in-meteor.readthedocs.org/en/latest/meteor-data/
I also tried passing the topicName in via props, but that also doesn't trigger a reactive update.
for others coming here, related threads
https://github.com/meteor/react-packages/issues/19
https://github.com/meteor/react-packages/issues/66
https://github.com/facebook/react/issues/2517
edit: props seems to be reactive
```
getMeteorData() {
var topicName = this.props.topicName;
var handle = Meteor.subscribe('RebotTopicDetail', {name: topicName});
/// and in the container passing in a prop
<TriggerList topicName={this.state.topicName} />
```
works. not sure if using state of the container item had something to do with it.

What's the Difference between Template.Instance() vs template.data?

When creating a Meteor event handler, what's the difference between...
'click .something': function(e,t){
var data = t.data
}
vs
'click .something': function(e,t){
var data = Template.instance().data
}
They both seem to bring up the same data. Is there a reason why I should one or the other?
Similar question here:
Difference between Template.instance() and this
The thing to realize is that:
In the template life-cycle functions (onCreated, onRendered...) this is equal to Template.instance() so this.data is the same as Template.instance().data AT THAT TIME!
In a helper or event, this is the current data context.
So, note an important thing here: the Data context can change over time if your data changes upstream:
If you pass data to a template, the template will be re-rendered with the new data. New data = new data context.
So if you do something like:
Template.example.onCreated(function() {
this.data.myKey = "my example data set on template creation"; //WRONG!
// or equivalently:
Template.instance().data.myOtherKey = "another key"; //WRONG!
})
well, this data may be under this (i.e. the data context) in your helper (this.myKey) but only as long as the upstream data does not change.
As soon as the upstream data changes, this will be the new data context, and will NOT contain your added data.
So, in summary:
If you need to add context to your template in onCreated or onRendered, make sure you do NOT bind it to the current data context, but to the Template.instance()
you should do:
Template.example.onCreated(function() {
this.myKey = "my example data set on template creation";
// or equivalently:
Template.instance().myOtherKey = "another key";
})
and you can access this data in helper and events via
Template.instance().myKey
It's actually Template.instance() (with a lower i), and as this function returns the current template instance in scope (the one where the event originated), there's no difference with the second parameter of an event handler, which also holds the current template instance, this is why you can access the template data indifferently using Template.instance().data or t.data in an event handler.
There is however a simpler way to access the current data context inside an event handler : the this object is bound to the data context where the event was triggered.

Meteor: How to make a helper function reactive?

I'm trying to get a helper to re-run and return the updated collection whenever this collection is updated.
For example:
Template.imagegallery.myimages = function() {
return Images.find({owner: Meteor.userId()}).fetch();
}
When I add data to the Images via a Meteor.call on the server side, my collection updates locally on the client, but the helper function does not re-run and the images don't update.....
any idea what i need to do to put the return collection from the helper object into a re-active context?
Return a cursor instead of a array:
Helper:
Template.imagegallery.myimages = function() {
return Images.find({owner: Meteor.userId()});
}
Template:
<template name="imagegallery">
{{#each myimages}}
!!!DOSTUFF!!!
{{/each}}
</template>
Fetch breaks reactivity in almost all cases. Because when you use fetch the Blaze only receives a array. So Blaze never creates the dependencies required for reactivity because it doesn't know that is data coming from a collection as that information is lost when you use fetch.
*Blaze is meteor's templating system

Resources