Render a meteor reactive variable from a database field - meteor

If I have a field in my DB that contains a string like "Hello {{currentUser}}," is there a way to allow that value to retain reactivity when rendered into a template? I am also looking to see if I can somehow inject my own variable into the output by running it through a helper and handling string replacement.
Thoughts?

One solution I've come up with thus far:
The message stored in the db is something like: "Hello, [user], how are you?"
I then render the message from the DB as usual with {{#each}} and a predefined template.
When the message is actually rendered, I pass it through a helper. The helper replaces all []'s with <span class="$1"></span> so that I can target each item directly.
Once the message template's rendered() is called, I know that the message body contains the cleaned and prepped content (with the spans), so I use this.$('.user').each() and loop over each instance of the spans.
I've also created a special template in my page called 'placeholderUser' that only contains a call to {{user}}. I've added Template.placeholderUser.user = function(){} to the code to pull through a value and maintain reactivity.
Whew! Now that I have the structure set up, when looping through in the "each," I can call:
UI.insert(UI.render(Template.placeholderUser), el), which will render the template in the given span and maintain all reactivity.
It's super hacky, but it works. Any other, better, solutions out there?

Related

Meteor: Call template helper from other template

I have two templates and I've defined JavaScript helpers and events to go with each. When a button is clicked in template A, one of the things I want to do is call a helper function for template B which will change what's displayed on the screen. Is this possible?
If it's not possible, I'd instead like to reload template B.
How can I do either of these? Do I use Tracker.autorun? Reactive variables? Ideally I would do, inside an event function for template A,
B.helpers.call("helperFunctionFromTemplateB");
There are a lot of solutions to what I think you want to achieve, but the answer really depends on context.
If template A is a child template of B:
You can pass a reference to a ReactiveVar in the parent template down to the child template's data context and modify it using {{>childTemplate reactiveVar=reactiveVar}} where reactiveVar is a helper in the parent template that returns the reference to the reactive variable
If the thing you want to change is in the parent's data context, you can use Template.parentData(n) where nis the amount of levels you want to jump up. While modifying the parent's data may not immediately seem reactive, you can make the data prop reactive by accessing it via Template.currentData()
Use some kind of globally accessible state. The most common answer would probably be to use the Session package and use Session.get('var') and Session.set('var', val).
Use an event emitter. This approach gets +'s for decoupling and reusability, but it's also potentially heavy handed if you only need to modify this variable in one place from one source (i.e. your requirements are simple)
Meteor 1.3 - If you want to make references to your reactive data in multiple places but don't want to create a global like Session, use a ReactiveVar or Reactive Dict (closer to session), create your variable where it makes sense, export it, and import it in your templates/anywhere else to be used.
There's a lot of other solutions, these are just the first that come to mind. If you provide more specific context, I'll provide a code sample of what I think's best and explain why. :)

Meteor autoform does not wait for element to exist in DOM

I'm adding a rendered template to the document via:
Blaze.renderWithData(Template.page, Session.get(toAdd[i]), document.getElementById('pages'))
This works great... except sometimes with autoform. I'm unsure what's triggering it to happen but some of my autoforms (that can exist inside Template.page, they're added to that template dynamically via the data passed in) show, while other throw a client error:
Uncaught TypeError: Cannot read property 'formValues' of undefined :: autoform-inputs.js:162
markChanged :: autoform-inputs.js:169
updateTrackedFieldValue :: afFieldInput.js:72
There's a timeout set to 0 in that afFieldInput.js on line 71. Upping this to 500 fixes the error above but is hacky and causes other issues.
The best I can surmise, autoform is attempting to get the form from the DOM by id before it exists in the DOM, probably it exists as a document fragment via Blaze, if I had to guess.
I can confirm that AutoForm.templateInstanceForForm is getting the correct form ID, but that document.getElementById(formId) is returning null.
The other possibility is that Blaze is, for some reason, failing to render the template but not warning me.
I was WAY off.
I had changed the schema, but was trying to open a doc with improper data for the new schema. Going to post this answer in case someone comes across the same error.
Also, don't pass in objects or functions all the way to the template that autoform doesn't expect, apparently. You can access them still, but remove them from the attr object by declaring attr as a function in the helper, returning this.attr sans any objects that don't need to be sent on to the template.

How can I set the data into a template dynamically?

I have a list of Task objects.
I have a template which contains a modal form to edit a task.
When a user clicks the link to a single Task I want to set the task to be edited to the Task that was clicked and then render the form.
I'm trying it with reactive variables and Tracker.depend. But I haven't quite gotten it working yet. The data on Template.taskUpdateForm doesn't get set properly.
Please see this commit to see what I'm working on.
https://github.com/laran/eisenhower/commit/e89890d49f5b772849d09fd1f719a6cdafa58125
When you click on a task to edit, just store it's _id or the whole task in a Session variable, and in the helper function for your modal use that same session variable. No need to worry about Tracker depend. This always works for me.
I was setting the selectedTask to the wrong thing. I just needed SelectedTask.set(this.task) instead of SelectedTask.set(this)

Meteor collection returns no results except in template

I'm new to the Meteor framework, and am having problems accessing data from my collection, outside of a template.
I have a small mongo collection and can retrieve and present its data without problems by using a template. However, when I try to get a cursor or array to use more directly, I get no results returned.
In my script, using find
var dataFind = Fakedata.find();
console.log(dataFind);
console.log(dataFind.count());
gives a cursor object, but a count of zero.
var dataFetch = Fakedata.find().fetch();
console.log(dataFetch);
console.log(dataFetch.length);
gives an empty array, length of zero.
Using the same find() or fetch() from the JS console gives populated objects as I would expect the code above to do. Within a meteor template, everything seems to work fine as well, so the pub/sub seems to be correct.
Any clues as to what I'm doing wrong here?
It looks like your subscriptions aren't ready at the time you try to access your collection data, this is a common gotcha.
When you access your collection data via templates, it is most likely via the use of template helpers which happen to be reactive, so they will rerun when your collections are ready thus displaying the correct data.
When accessing your collections in a non-reactive script though, they will appear empty if the subscription is not yet ready.
You can try using this pattern in your script to execute code only when the subscription is ready :
Meteor.subscribe("mySubscription",function(){
// we are inside the ready callback here so collection date is available
console.log(Fakedata.find().fetch());
});
If you are looking for a more robust approach, try looking at iron:router waitOn mechanism.

Collection.findOne() does not return any results in Template.created

I have a template which is a simple edit form. The _id of the document to be edited comes in a session variable (set by mini-pages from the URL: http://example.com/items/4zt4z3t3t). In the Template.editForm.createdfunction I try to get the correponding document from the collection using ItemCollection.findOne({_id:_id}). The _id is set correctly in all cases.
When I navigate to http://example.com/4zt4z3t3t and debug the created function, ItemCollection.findOne()returns undefined, although there are items in the collection. Therefore I can never find my item by _id. Also, when I move the item find procedure to the routing stage, there is also no result for the find. Later on, the colleciton works as expected.
Any pointers?
Meteor uses a Data on the wire principle. This means when your HTML has loaded your data isn't sent along with it, at least initially.
You can't therefore access data in a .created function, unless you expect that template to be loaded after the data has been downloaded. This is why it returns undefined initially but if you check later its there.
You can either, wait for a callback from the subscription on when the data is completed, then load the template.
OR
Use reactivity in your template and let it load empty, and automatically fill it up with data when the data has come in (really the easiest). Access your data in the template and use a handlebars helper to fill in the data and use the .rendered callback to do any changes after.

Resources