Using third party javascript package with Meteor - meteor

I'm working with Meteor at the moment, and I'm trying to make it look more 'real timey' by adding transitions to numbers as they change. The best third party package I can see for that is http://github.hubspot.com/odometer/.
I'm having trouble getting the package to work in Meteor to update comment numbers on an item.
I've tried putting the javascript into client/compatibility as per the meteor docs: http://docs.meteor.com/#structuringyourapp, but no joy.
The other issue might be that the package uses CSS transitions, which would mean that a re-rendering of the template around the number that is updating would prevent the transition from occurring. To try and fix this problem, I used {{#isolate}} around the number, but that didn't work either.
Has anyone got any other ideas on what else in meteor might be getting in the way?

I think you should try {{#constant}} instead of {{#isolate}}. Also note, that the "constant" part of your template will no longer be reactive, so you'll have to update it manually. Supposing that you have a template
<template name="myTemplate">
{{#constant}}
<span class="odometer"></span>
{{/constant}}
</template>
you will need to do something like this:
Template.myTemplate.rendered = function () {
var node = this.find('.odometer');
Deps.autorun(function () {
node.innerHtml = MyCollection.find({}).count();
});
}

Related

How to get current year in a Nunjucks template within Apostrophe CMS

I am in the process of adding a copyright line to the footer of a website that I have been working on and I cannot find the best way to get the current dynamically into the footer so I never have to set it again. I have tried multiple things, including a global setting that can be accessed from anywhere, but nothing has worked.
Any feedback would be appreciated. Thanks.
Write an ApostropheCMS nunjucks helper function. See those docs for the general issues around this. Your specific function could look like:
self.addHelpers({
thisYear: function() {
return new Date().getFullYear();
}
});
If you put that in construct of a module of your own, let's say it's called helpers, then you can call it in Nunjucks as {{ apos.helpers.thisYear() }}.
These are very handy, just remember they cannot do any async work.

Ember js, show spinner when something is loading in background

Is there a way with EmberJS to show a loading template somewhere when something in my page is loading something?
For example, I have a page with many many songs artists, and each of them have many many songs. I load the page of the artists, and good, but in background I'm loading info about songs of everyone. I simply need a loading spinner somewhere that says to me the site is loading something (for example, there is in "Network" tab of Chrome Developer Tools something pending...)
how to do that in such an elegant Emberjs way?
You can observe the isPending property of Ember.PROMISEPROXYMIXIN like so:
{{#if artist.songs.isPending}}
loading...
{{/if}}
As far as I know (and based on a quick perusal of the API docs) Ember doesn't provide a built-in way to achieve this. Unless I'm wrong, this means you'll need to implement request state tracking yourself.
You could do this in Ember's adapter layer (e.g. add code in app/adapters/application.js), but the simplest solution might be to just work with jQuery directly. There are a few APIs you can use:
jQuery.active, which indicates the number of outstanding requests
ajaxStart and ajaxStop
I'd recommend creating an Ember.Service to track this state-- then you can inject it in any Controller or Component that needs to render a template based on this info. Your Service could look like:
import Ember from 'ember';
export default Ember.Service.extend({
init() {
this._super(...arguments);
const invalidateRequestInProgress = () => {
this.notifyPropertyChange('dummyProperty');
}
$(document).ajaxStart(invalidateRequestInProgress);
$(document).ajaxStop(invalidateRequestInProgress);
},
requestInProgress: Ember.computed('dummyProperty', function() {
return Ember.$.active !== 0;
}),
});
I haven't tested this code, so I'm not sure if it'll work in practice :)

Meteor's iron:router isn't doing {{renderRouter}} as expected or documented

I've got a very simple template problem going on that appears to be similar to this guy's problem, though I've tried to build a simple example to demonstrate the problem and hopefully have someone explain to me how to fix or work around it.
Although as I'm doing some online research, it may be that the official documentation is out of date with the code. The reason I haven't bought into accepting that just yet is that the problem seems to have existed for a while, the dates on such articles in forums appears to be fairly old, and there's talk of it being fixed. There's also talk the feature is gone. What's the new way, if there is one?
I'm using Meteor 0.9.0.1 with iron:router 0.9.1. Specifically, I set up my project like this:
$ meteor create ironTest
$ cd ironTest
$ meteor add iron:router
$ meteor
Pointing my browser at http://localhost:3000/ as instructed, shows the default project. So far so good.
Now make ironTest.html contain this:
<body>
<h1>Before</h1>
{{renderRouter}}
<h2>Afterward</h2>
</body>
<template name="hello">
Hello Template
</template>
<template name="goodbye">
Goodbye Template
</template>
Make ironTest.js contain this:
Router.configure({
autoRender: true // we will experiment with this Boolean shortly
});
Router.map(function () {
this.route('hello');
this.route('goodbye');
});
If you go to the routes http://localhost:3000/hello and http://localhost:3000/goodbye, you'll see the templates correctly render as expected and documented, appended to the <body> element, so it appears after the <h2> element.
According to the current documentation for iron:router, one should be able to set the autoRender property to false, and the template should no longer be appended to the <body> element, but rather be injected where the Handlebars (okay, Spacebars) element {{renderRouter}} is, that is, between the <h1> and <h2> elements.
When I try this, visually it doesn't do anything. Opening a JavaScript Console to look at errors shows none. Although, by deliberately going to an invalid route it will show a missing template router exception, showing the routing code is indeed working.
Does anyone know how to coerce the code above into working?
For the curious, I've got a working simplistic equivalent that might be of use to others working this problem.
This new ironTest.html uses a template (for a layout) with no <body>:
<template name="main">
<h1>Before</h1>
{{> yield}}
<h2>Afterward</h2>
</template>
<template name="hello">
Hello Template
</template>
<template name="goodbye">
Goodbye Template
</template>
This ironTest.js instead uses a layout:
Router.configure({
layoutTemplate : 'main'
});
Router.map(function () {
this.route('hello');
this.route('goodbye');
});
It's worth an aside that this solution doesn't work for me, as I don't want a global layout, and have concern that riddling layouts in the route themselves is a tighter coupling than desired for my purposes.
I'm currently looking for a way to dump debugging log information from the Router as it performs transitions, but that's another story.

Meteor+Blade template variables catch 22

I'm trying to use a variable in my Blade template, but I always get
ReferenceError: files is not defined
My understanding is that the proper way to pass a variable to a template is something like this (client/ceres.js):
Meteor.startup(function() {
Files = new Meteor.Collection('files');
Template['files'].files = function() {
return Files.find();
}
});
(Copying from the "todos" example)
And then I should be able to use it in my template, views/files.blade:
ul
foreach files as file
li= file.filename
But I guess the variable is passed to the template too late? But if I take my JS out of Meteor.js then Template isn't defined.
So I don't get it. Either my template doesn't exist, or the variable doesn't exist, and it always crashes. How do I pass a simple variable along?
Same error with this:
ul
- for(var i=0; i<files.length; ++i)
li= files[i].filename
This is a known issue with Meteor that is actively being worked on.
The problem is that Meteor prevents smart packages from specifying the load order of files. See issue here.
Because of this issue, it is possible that your client-side JavaScript will run before the templates are loaded. (There is a hack in Meteor that ensures Handlebars templates load before your custom code) For example, Template.foo.helperName = function() { ... } will fail if Template.foo has not yet been defined.
Check the generated HTML (view source) for the initial page load to see if your client-side JavaScript code is loading before the template is defined. If so, you may get an Error like:
TypeError: Cannot set property 'helperName' of undefined`
To workaround this issue, try putting your client-side code in a folder with a different name. I believe that Meteor currently sorts files alphabetically when determining the load order. See the troubleshooting section on this page for more information.
A similar workaround is to utilize Meteor.startup when adding view helpers to your views. That is, you can wrap your Template.foo.helperName = ... stuff in a Meteor.startup call. If you are using a body.blade template, though, you can end up with the opposite problem (i.e. the "catch 22") in which your body.blade template starts rendering before view helpers get setup. In this case, you can get errors since those helpers/variables are not yet defined. The solution here is to avoid using body.blade templates and only render the initial template once all view helpers have been loaded (i.e. at the end of your Meteor.startup routine).
At any rate, all of these workarounds are rather lame. :( But, alas! These issues should be fixed soon.
As soon as Meteor fixes the issue described above, I will modify the Blade smart package to enforce the load order of compiled templates. My apologies for the confusion.
Turns out you can't include files that use Template variables either. i.e., you can't use the include directive in Blade at all if you want to use variables in your template that haven't been initialized by Meteor yet -- you have to insert your template via jQuery/JS after the DOM has loaded. Example:
views/body.blade:
.container
h1 Page Title
#content
views/files.blade:
ul
foreach files as file
- console.log(file);
li= file.filename
client/main.js:
Files = new Meteor.Collection('files');
Template.files.files = function() {
return Files.find();
};
$(function() {
$('#content').html(Meteor.render(Template.files));
});

With Meteor, why calling MyCollection.findOne affects other template functions?

I am using findOne just to fetch one certain element for my collection.
However, when I do that, all my template functions containing those collections are re-run and the content refreshed. The content is similar, the problem is I am applying styles to some of those elements, and these updates just reset everything as well. More importantly: those refreshes are completely useless.
For example, I have this template:
Template.content.cars = function () {
alert("I AM RERUN!");
return Cars.find();
};
And in another function, I am doing this:
Cars.findOne({ _id: Session.get('current_car') }, {});
Why would be the first template re-run? Am I doing something wrong?
I'm not sure why your first template would be re-run: are you sure something else isn't going on?
But as a general non-answer to your question: you should expect that a template which depends on the entirety of a collection will be re-run many times (for instance as the data loads incrementally when the page first renders). With meteor you need to write your HTML/CSS in such a way that this re-rendering won't cause problems.
Without knowing more about your problem I can't really say more than that.

Resources