Dojo require in AMD plugin not firing callback - asynchronous

In the following plugin, the load method is correctly called, but the inner callback is never fired:
define("App/FooLoader", [], function() {
return {
load: function(id, require, callback) {
require(["App/Foo"], function(foo) {
callback(foo);
});
}
}
});
With the above, I was expecting that when included, like so:
// in Bar.js
require(['App/Fooloader!'], function(foo) { // do stuff with foo });
That:
App/FooLoader is loaded, and the load method is executed
App/Foo is loaded, and the inner callback is executed
App/FooLoader body callback is executed with foo the result of loading App/Foo.
However, only (1) happens, the callbacks (2) and (3) never happen. How come?

It works for me as below:
define("App/Foo", [], function() {
return 'bar';
});
define("App/FooLoader", [], function() {
return {
load: function(id, require, callback) {
console.log('inside load', arguments);
require(["App/Foo"], function(foo) {
console.log('inside require, foo=', foo);
callback(foo);
});
}
}
});
require(["App/FooLoader!"], function(fooload) {
console.log('fooloaded', fooload);
})​
I created this JSFiddle to demonstrate: http://jsfiddle.net/fMR3Z/1/
Maybe you have an error in your file structure ?

Related

gulp task with a parameter and callback

I'd like to add a parameter to a gulp task that is already using a callback function to indicate when tasks are completed, is there any way to do this?
Current:
gulp.task('build', build);
function build(done) {
// do stuff here
done();
}
Desired:
gulp.task('buildA', build(optionsA));
gulp.task('buildB', build(optionsB));
function build(options, done) {
// do stuff here with params
done();
}
This gives an error of 'done is undefined'.
You have few ways to do this:
First, make a closure a invoke before like this:
gulp.task('buildA', build(optionsA));
gulp.task('buildB', build(optionsB));
function build(options) {
return function (done) {
// do stuff here with params
done();
}
}
Second, bind your current functions with the options desired:
gulp.task('buildA', build.bind(null, optionsA));
gulp.task('buildB', build.bind(null, optionsB));
function build(options, done) {
// do stuff here with params
done();
}

iron router syntax: onAfterAction

Router.route('/courses/:_catalog', function () {
var courseCatalog = this.params._catalog.toUpperCase();
Meteor.subscribe("courseCatalog", courseCatalog);
this.render('CourseDetail', {
to: 'content',
data: function () {
return Courses.findOne({catalog: courseCatalog});
}
});
}, {
onAfterAction: function() {
if (!Meteor.isClient) {
return;
}
debugger
var course = this.data(); <======
SEO.set({
title: "course.catalog"
});
}
});
In the above code, please look at the debugger statement. I want to access the data but it seems I am doing something wrong because this.data doesn't exist. I also tried Courses.find().fetch() but I only get an empty array inside onAfterAction. What's the right syntax and what am I missing?
It needs to be inside a this.ready() block:
onAfterAction: function() {
if (this.ready()) {
var course = this.data();
...
}
}
You need to subscribe to data first. Have a look at the waitOn function to do this. The server only sends the documents you subscribed to, and since you didn't subscribe, Courses.find().fetch() returns an empty array.
Also, don't put SEO stuff in onAfterAction. Put it in onRun which is guaranteed to only run once.

Session object inside global template helpers

Session.set('coursesReady', false); on startup.
UPDATE:
I made it into a simpler problem. Consider the following code.
Inside router.js
Router.route('/', function () {
Meteor.subscribe("courses", function() {
console.log("data ready")
Session.set("coursesReady", true);
});
}
and inside main template Main.js
Template.Main.rendered = function() {
if (Session.get('coursesReady')) {
console.log("inject success");
Meteor.typeahead.inject();
}
The message "inject success" is not printed after "data ready" is printed. How come reactivity does not work here?
Reactivity "didn't work" because rendered only executes once (it isn't reactive). You'd need to wrap your session checks inside of a template autorun in order for them to get reevaluated:
Template.Main.rendered = function() {
this.autorun(function() {
if (Session.get('coursesReady')) {
console.log("inject success");
Meteor.typeahead.inject();
}
});
};
Probably a better solution is to wait on the subscription if you want to ensure your data is loaded prior to rendering the template.
Router.route('/', {
// this template will be rendered until the subscriptions are ready
loadingTemplate: 'loading',
waitOn: function () {
// return one handle, a function, or an array
return Meteor.subscribe('courses');
},
action: function () {
this.render('Main');
}
});
And now your rendered can just do this:
Template.Main.rendered = function() {
Meteor.typeahead.inject();
};
Don't forget to add a loading template.
To Solve Your Problem
Template.registerHelper("course_data", function() {
console.log("course_data helper is called");
if (Session.get('coursesReady')) {
var courses = Courses.find().fetch();
var result = [ { **Changed**
name: 'course-info1',
valueKey: 'titleLong',
local: function() {
return Courses.find().fetch();
},
template: 'Course'
}];
Session.set('courseResult', result); **New line**
return Session.get('courseResult'); **New line**
,
Explanation
The answer is at the return of the helper function needs to have be associated with reactivity in order for Blaze, template renderer, to know when to rerender.
Non-reactive (Doesn't change in the DOM as values changes)
Template.Main.helpers({
course_data: UI._globalHelpers.course_data ** Not reactive
});
Essentially: UI._globalHelpers.course_data returns an array of objects which is not reactive:
return [
{
name: 'course-info1',
valueKey: 'titleLong',
local: function() {
return Courses.find().fetch();
},
template: 'Course'
},
Reactive
From Meteor Documentation:
http://docs.meteor.com/#/full/template_helpers
Template.myTemplate.helpers({
foo: function () {
return Session.get("foo"); ** Reactive
}
});
Returning Session.get function to Blaze is reactive; thus, the template will change as the values changes.

iron-router except fails?

So i'm just getting started with iron-router, and I've been building a login system. It works via a .onBeforeAction hook before every route, checking if the user is logged in. However, there are a few routes I want public, so I've added an except option, as per the docs. Except the problem is it doesn't work :( can anybody see why?
Router.route('/new', function () {
name: 'new',
this.render('newComp');
});
Router.route('/c/:_id', {
name: 'compPage',
data: function() { return Comps.findOne(this.params._id); }
});
Router.route('/c/:_id/embed', function () {
name: 'embed',
this.layout('empty'),
this.render('compEmbed', {
data: function () {
return Comps.findOne({_id: this.params._id});
}
});
});
function loginFunction(){
// all properties available in the route function
// are also available here such as this.params
if (!Meteor.user()) {
// if the user is not logged in, render the Login template
if (Meteor.loggingIn()) {
this.render(this.loadingTemplate);
} else {
this.layout('empty');
this.render('login');
}
} else {
// otherwise don't hold up the rest of hooks or our route/action function
this.next();
}
}
Router.onBeforeAction( loginFunction, {
except: ['embed'] // this aint working
});
The problem seems to be in your route definition, the name param should be in the third param of Router.route(), like this (so your route actually didn't have a name, thus the except:['route.name'] doesn't work):
Router.route('/c/:_id/embed', function () {
this.layout('empty'),
this.render('compEmbed', {
data: function () {
return Comps.findOne({_id: this.params._id});
}
});
}, {
name: 'embed',
});
More info about named routes here: http://eventedmind.github.io/iron-router/#named-routes

Subscription manager doesn't update collection after new subscription

In my Meteor application I have this situation in which I have a 'Settings' collection only on the client. So the publish function is:
Meteor.publish('settings', function (option) {
this.added("settings", "settings", {
bar: true,
foo: { .... }
});
this.ready();
});
Initially I subscribe like:
waintOn: function () {
return subs.subscribe('settings')
}
But when the route changes I subscribe again like
return subs.subscribe('settings', 10);
After this I see that the publish function runs, but on the client nothing happens.
For some reason the server thinks that the data did not change and decides to do nothing. So the question is how can I tell Meteor that the data has changed so it sends the data to the client. If the problem is completely different, I'm also very interested!!
UPDATE: the publish function might look like this:
Meteor.publish('settings', function (option) {
var list;
if (option === 10) {
list = [1,2,3,4,5];
}
this.added("settings", "settings", {
bar: true,
foo: list
});
this.ready();
});
UPDATE2: Expected solution:
var isNew = true;
Meteor.publish('settings', function () {
if(isNew) {
this.added("settings", "settings", {
bar: true,
foo: list
});
isNew = false;
}
else {
this.changed('settings', 'settings', {.....});
}
this.ready();
});
It would even be better if there was a function like this.exists('settings', 'settings') because the isNew variable feels a bit like a hack!
Anyway, I have it working now as follows:
try {
this.removed('settings', 'settings');
} catch(e){}
this.added('settings', 'settings', {...});
...

Resources