Pass reactive data to Meteor Template - meteor

I need track change on data passing to template
Example
{{>myTemplate data1="staticData" data2=reactiveHelper }}
Where data1 is static bu data2 come from a helper in parent template like:
Template.parentTemplate.helper({
'reactiveHelper':function(){
return Session.get('any-reactive-value')
}
})
Then I need a a autorun who track myTemplate.data.data2
Thanks for any help and sorry for my english

Related

Meteor Blaze Data Context becomes undefined

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.

Redux Adding UI properties to state object

Let's say I have an initial state in my redux application that looks like this:
{
themeParks : []
}
And theme park objects are stored in a MongoDB or wherever like this:
{
ParkName : "Disney World",
NumberOfRides : 25
}
My app fetches (via ajax) and displays the theme parks on load, and lets me do CRUD operations to add / remove / edit theme parks.
My question is, what is the best point in the application to merge in new properties that I will need, that are related to UI changes and need to be included in the state? For example, at some point I need to add an "editing" boolean property to each theme park, so they look like this:
{
ParkName : "Disney World",
NumberOfRides : 25,
editing : false
}
This "editing" flag needs to be a property of each theme park object, to provide the ability to have multiple theme parks in an editable state while using the application, is that correct? Obviously I don't want or need to store this flag in my database schema as it only relates to UI operations.
My first guess would be to include such logic within my .then function after successful return of the data, like this, but I'm not sure:
let ajax = new AjaxHanlder();
let promise = ajax.DoGet('/path/to/api-endpoint');
promise.then((themeParks) => {
themeParks.map((themePark, i) => {
themePark.editing = false;
});
dispatch({type : LOAD_THEME_PARKS, payload : themeParks});
});
Also, is there a convention for providing a definition of the theme park object before it is loaded, since the initial state is an empty array and has no knowledge of it?
Thanks in advance for any insight on this, as I attempt to advance my knowledge of redux design patterns :-)
I recommend adding the editing property to your LOAD_THEME_PARKS reducer. For example, part of your LOAD_THEME_PARKS reducer could look like:
case LOAD_THEME_PARKS:
return {
...state,
themeParks: action.payload.map(park => park.editing = false)
};

Meteor Dashboard and publication/subscription

EDIT: as the original question was too vague I have updated it to make it more concrete
I'd like to create a dashboard in Meteor that shows some statistics about my collections (e.g. how many docs, how many users...). I have been trying the past days but can't seem to find a good/intelligent way.
I initially just did the following:
Template.dashboard.helpers({
getProductsCount: function() {
return Products.find().count();
}
});
This did not work. I think because it counts the number of products from minimongo, but not sure.
Then I did the following:
In the template helper, call a method and get the value to show on the dashboard page (does not work)
Was told not to use pub/sub mechanism for this type of metric
Worked via Session variables (did work, but feels a bit strange to store this kind of metric data in Session variables
So then I read in another SO response about Reactive Variables and tried the following:
Template.dashboard.helpers({
getProductsCount: function() {
return Template.instance().myAsyncValue.get();
}
});
Template.dashboard.created = function() {
var self = this;
self.myAsyncValue = new ReactiveVar("Waiting for response from server");
Meteor.call('getProductsCount', function(error, asyncValue){
if (error)
console.log(error);
else
self.myAsyncValue.set(asyncValue);
});
};
This works, but I find this extremely difficult for something as simple as showing a product count (or any other metric). Not sure I understand the reason why I should use sth as reactive variables?
Then -out of curiosity- I tried the following (using meteor add simple:reactive-method) and it works:
Template.customerDashboard.helpers({
getProductsCount: function () {
return ReactiveMethod.call("getProductsCount");
}
});
So the question really is why having to use Reactive variables and methods for sth as simple as this. Can someone explain?
If you want to show the count only in the view, the best way is to return the count number only. you do not need publish/subscribe at all. you can use server methods. and if you want to show data also, you can go for pub-sub. and your approach is correct.

How to pass a fresh _id from a method insert into a subscription/publication?

I have an app where you can choose (or add if they don't exist!) a superhero/villain character from a certain universe on the first page; then outfit him with weapons, clothes, and gadgets on the second page (build).
I have this route defined:
Router.route('/build/:character', {
name: 'build'
waitOn: Meteor.subscribe('characters', {name: this.params.character})
//and a few other subscriptions and sessions as well for the items
//and stuff, but those don't matter here.
}
The link from the specific character, though, passes along a query as well:
<a href="{{pathFor 'build' query=this.universe}}">
So the final link could look something like this:
/build/Aquaman?DCComics
Now the page you are on will display a list of weapons and gadgets where you could also add other stuff if you so wish. Then you are supposed to drag the items you want to include onto your version of this hero.
Problem is, at this point the app doesn't know you even want to create your own hero. Maybe the user is just looking through them for fun. There's a button that the user has to click first to initialize the creating process, and that's when the actual _id is created, something like this:
Meteor.methods({
buildHero: function(heroCharacterName, heroUniverse) {
var heroToAdd = {}
heroToAdd['characterName'] = heroCharacterName
heroToAdd['universe'] = heroUniverse
heroToAdd['_createdAt'] = new Date()
CreatedHeroes.insert(heroToAdd, function() {
if (! error)
//Update the subscription somehow...
})
}
})
So, the _id that is created here in the new Collection must be passed along to a subscription somehow, because I don't want the user to see other personal heroes that have been created, only his own newly created one.
The solution I have in mind is adding the _id onto the URL in form of a hastag, and use this.params.hash in the subscription like so:
Router.route('/build/:character', {
name: 'build'
waitOn: [Meteor.subscribe('characters', {name: this.params.character}),
Meteor.subscribe('createdheroes', this.params.hash)]
}
First of all, is this a valid approach? If so, how do I accomplish it; how do I actually update the URL to include this hash?
If not, what would be a better approach?
I think you have to handle this logic in the data context or in a template helper and not in the way of subscribing/publishing.
If I was you I would besure that the newly created item is being published and subscribed by the client and modify your search query just that it only adds the newly created item.
I am not sure if I understand your question well but what I got, you will know the last _id which was used on your insert.
Instead of letting done this automatically by meteor, just use the meteor method to create / get that _id value >> see Meteor Documentation
var new_id = new Mongo.ObjectID()
col1.insert({ _id: new_id, ... });
col2.insert({ ..., ref_col1_id: new_id, ... });

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.

Resources