I have the latest version of Meteor...
meteor --version
Meteor 1.1.0.2
This is what the documentation says...
Template.codeSample.onRendered(function () {
hljs.highlightBlock(this.findAll('pre'));
});
This is my js code...
if (Meteor.isClient) {
Template.virtuebox.onRendered(function () {
console.log("hi")
});
}
This is my template...
<template name="virtuebox">
<div class="box">
<span>{{text}}</span>
<input type="number" value="0.5" step="0.1" min="0" max="1" name={{text}} />
</div>
</template>
This is the method list...
This is the error...
simple-todos.js:34 Uncaught TypeError: Template.virtuebox.onRendered is not a function
What am I doing wrong?
This is curious... I'm seriously wondering if you somehow don't have a good blaze on your system.
Really, the new
Template.foo(onRendered(function(){}));
mechanism makes sense as it provides for multiple callbacks instead of the old
Template.foo.rendered = function(){};
which only gave you one - but that's not causing your problem.
The absence of some of the visible parts of Template.prototype (namely the onCreated, onRendered, onDestroyed and _getCallbacks functions and the _callbacks object) makes me think that packages/blaze/template.js on your system has somehow been compromised.
You might try seeing if the old Template.foo.rendered works, Though the in-code documentation of the _getCallbacks function states
// Fire all callbacks added with the new API (Template.onRendered())
// as well as the old-style callback (e.g. Template.rendered) for
// backwards-compatibility.
I don't see how this would be any better; it's not clear what's on your system.
Failing that, I'd try removing meteor from your system and reinstalling it fresh. If its the meteor source on your system that's thwacked, a reinstall should fix it.
Related
I've seen this problem posted but did not really understand the explanations. I am new to meteor and doing this project. From what I understand some of the functionality with node is not available in the browser, but I am unsure of how to fix the problem. I have tried to wrap the code within some function(window) but still was not able to get it working. I also tried to use npm but was coming up empty with some errors about some Illegal tokens. Thanks for any help.
Your app is crashing. Here's the latest log.
/home/alex/TacticsTrainer2/.meteor/local/build/programs/server/boot.js:186
}).run();
^
ReferenceError: window is not defined
at app/js/bootstrap.min.js:6:353
at app/js/bootstrap.min.js:8:3
at /home/alex/TacticsTrainer2/.meteor/local/build/programs/server/boot.js:155:10
at Array.forEach (native)
at Function._.each._.forEach (/home/alex/.meteor/tools/5bf1690853/lib/node_modules /underscore/underscore.js:79:11)
at /home/alex/TacticsTrainer2/.meteor/local/build/programs/server/boot.js:82:5
=> Exited with code: 8
=> Your application is crashing. Waiting for file change.
It looks like you may have not structured your app correctly. You have code that is intended to run on the client/browser side that is running on the server side.
In your app:
place all code to be run on the client in the /client directory
place all server side code in the /server directory
place code that you want to run on both the server and client in the root folder or a non reserved name (public, private, tests, server or client)
For more details about this see the meteor docs: http://docs.meteor.com/#structuringyourapp
ReferenceError is a Node error. Meteor is a framework on top of Node.
Node has a global scope (aka Node's global variable). This error is thrown by Node (not Meteor) if you try to access an undefined global variable.
Browsers also have a global scope called window, and do not throw ReferenceErrors when undefined variables are accessed.
Here's a pattern I like for adding functionality to a class (it's very Meteor):
/lib/Helpers.js <-- Helpers for everyone (node+browser)
/server/Helpers.js <-- Server helpers (node)
/client/Helpers.js <-- Client helpers (browser)
Consider these implementations:
// /lib/Helpers.js
Helpers = {/* functions */}; // Assigned to window.Helpers and global.Helpers
// /server/Helpers.js
Helpers = _.extend(Helpers, {/*more functions*/}
// /client/Helpers.js
Helpers = _.extend(Helpers, {/*more functions*/}
This is a trivial example. What if I didn't want to worry about load order? Why not _.extend() in /lib/Helpers.js?
// /lib/Helpers.js
// Helpers = {/* functions */}; // Overwrites...
Helpers = _.extend(Helpers, {/* functions */}); // ReferenceError
Because you'll get a ReferenceError from Node if Helpers isn't defined - specifically the "Helpers" used as an argument. (Node knows to assign Helpers as global.Helpers).
Here are two ways to "fix" this:
1) Assign Helpers to something
// /lib/Helpers.js
if (typeof Helpers === 'undefined') Helpers = {};
Helpers = _.extend(Helpers, {/* functions */});
2) Use helpers from the global
// /lib/Helpers.js
Helpers = _.extend(global.Helpers, {/* functions */}); // works in node, but...
Both of which suck.
1)'s syntax is horrible.
2) works in node, but there is no global in browsers. So it fails it's purpose.
So I gave up and went back to overwriting it the first time in lib, and looking for runtime errors if anything was overwritten.
If you have a handy cross-browser syntax for this, do comment :-)
I think you are calling a method that is loaded on the client and server.
You could write the code inside the Meteor.method like this:
if (!this.isSimulation) {
// code with node js that should only run in the server
} else {
// code that doesn't have nodejs runtime (browser)
}
This happens when you loaded the Method both in the client and server.
I have a simple template which has a search box in it:
<template name="search">
<input type="text" name="search" id="search" />
{{> search_results}}
</template>
and obviously, the search results template:
<template name="search_results">
<ul>
{{#each results}}
<li>{{this.resultValue}}</li>
{{/each}}
</ul>
</template>
There is an event for keyp on the search input:
Template.search.events({
'keyup input#search': function (e) {
// fetch result from db
}
});
My problem is, where i have the comment: fetch result from db how do i get the search results template to auto update with the results from the db query?
To be clear: i can get the results fine, just cant see how to get the results template to update.
Essentially, something in the template you want to rerender (search_results) has to be reactive and register a changed event. Out of the box, that means it could be any of the data sources listed here. Since this isn't happening for you, I assume that when you "fetch results from db" you're not actually returning the result of a minimongo query, as this would be reactive by default.
If so, this kind of problem is often most easily solved by rolling your own reactivity using the Deps.Dependency prototype, which (as I understand it) underpins all the other reactive data sources other than the minimongo itself.
If you set var resultsChanged = new Deps.Dependency(), you get an object with two methods: depends and changed. Invoke the former in any computation you want to rerun when it changes and the latter to register a change. Session variables are basically just key/value stores with these Deps.Dependency methods attached to their get and set methods respectively.
So if you have resultsChanged initialised, you just need to make sure your search_results template depends on it, either by adding a new helper function (if results is in the data context as opposed to being a call to a helper), or amending the results helper itself. I'll assume the latter, but adding a new helper instead would be equally trivial.
Template.search_results.helpers({
results: function() {
resultsChanged.depend();
// get your results from wherever
return results;
}
});
That will rerun every time resultsChanged changes, so you just have to add the appropriate code in your callback when you fetch the results:
'keyup input#search': function (e) {
// fetch result from db, passing "resultsChanged.changed()" in a callback
}
Obviously, if the result fetching is synchronous, you don't even need to pass a callback, you can just do it on the next line.
I hope that is vaguely helpful - please let me know if it's not. If my assumption that you're not just pulling something out of the database is wrong, then this is probably on totally the wrong track, so I would recommend posting your actual "fetch result from db" code in your question.
I have some data that is being processed asynchronously in the background and want to delay the initialization of the entire AngularJS application until this finished.
BackgroundData.initialized is a Q promise, so something like this:
BackgroundData.initialized.then(AngularDoYoStuff)
The problem I run into is the home page's controller starts its initialization procedure, hits BackgroundData and either it has the wrong/no data.
What function can I wrap Angular's initialization in so, instead of just dom-ready, it waits for both dom-ready and BackgroundData.initialization?
UPDATE
I have gotten closer with the documentation on manual bootstrapping:
angular.element(document).ready ->
setupGA()
window.BackgroundData = new DataMachine()
BackgroundData.initialized.then ->
angular.bootstrap(document)
But when the controller files load (after this file), they are still getting initialized before BackgroundData is defined
UPDATE 2
Removing the ng-app directive in the HTML seems to have fixed the problem (since that was telling Angular to auto-init) but now it just ignores all of my angular.module calls
The problem was that I had left the ng-app directive in the html tag, which tells Angular to auto-initialize that scope. Removing it allowed my manual initialization to run correctly.
as Chris mentioned, it can be done with angular.bootstrap and not mentioning the ng-app:
<div id="appArea" ng-controller="someCtrl">
{{name}}
</div>
<script>
angular.module('someApp', [])
.controller('someCtrl', function($scope) {
$scope.name = "test name";
})
setTimeout(function() {
angular.bootstrap(document, ['someApp']);
}, 2000);
</script>
One way to approach this if you are using routes in your app is to have the app initialize but wait on defining routes until the data is available.
I.e. provide a user-friendly 'loading' message, and then load functionality after.
You are able to inject $route where required, and then call something like:
$route.routes["/RouteName/:param"] = {templateUrl:"template.html", reloadOnSearch:true, controller:"ControllerName"};
After that, call $route.reload() or $rootScope.apply() to refresh.
More information at https://groups.google.com/forum/?fromgroups=#!msg/angular/AokZpUhZ6mw/x2kPIN2VAC0J
I want to perform a Meteor collection query as soon as possible after page-load. The first thing I tried was something like this:
Games = new Meteor.Collection("games");
if (Meteor.isClient) {
Meteor.startup(function() {
console.log(Games.findOne({}));
});
}
This doesn't work, though (it prints "undefined"). The same query works a few seconds later when invoked from the JavaScript console. I assume there's some kind of lag before the database is ready. So how can I tell when this query will succeed?
Meteor version 0.5.7 (7b1bf062b9) under OSX 10.8 and Chrome 25.
You should first publish the data from the server.
if(Meteor.isServer) {
Meteor.publish('default_db_data', function(){
return Games.find({});
});
}
On the client, perform the collection queries only after the data have been loaded from the server. This can be done by using a reactive session inside the subscribe calls.
if (Meteor.isClient) {
Meteor.startup(function() {
Session.set('data_loaded', false);
});
Meteor.subscribe('default_db_data', function(){
//Set the reactive session as true to indicate that the data have been loaded
Session.set('data_loaded', true);
});
}
Now when you perform collection queries, you can check if the data is loaded or not as:
if(Session.get('data_loaded')){
Games.find({});
}
Note: Remove autopublish package, it publishes all your data by default to the client and is poor practice.
To remove it, execute $ meteor remove autopublish on every project from the root project directory.
Use DDP._allSubscriptionsReady() (Meteor 0.7)
As of Meteor 1.0.4, there is a helper that tells you exactly when a particular subscription is ready: Template.instance().subscriptionsReady().
Since this question is a duplicate, please check my answer in the original question, Displaying loader while meteor collection loads.
You can also do template level subscriptions:
Template.name.onCreated(function(){
var self = this;
this.autorun(function(){
const db = this.subscribe('publicationname', [,args]);
if(db.isReady()){
"You'll know it's ready here" .. do what you need.
}
});
})
This makes it easier to know inside the template too. you can just call
{{#if Template.subscriptionsReady}}
{{else}} Loading Screen may be
{{/if}}
You could check when a result is finally returned if you know that your Games collection is never empty:
Meteor.autorun(function() {
if(Games.findOne() && !Session.get("loaded")) {
Session.set("loaded",true);
//Its ready..
console.log(Games.findOne({}));
}
});
You can also use this in your templates:
Client js:
Template.home.isReady = function() { return Session.get("loaded") };
Html
<template name="home">
{{#if isReady}}
Yay! We're loaded!!
{{else}}
Hold an a second
{{/if}}
</template>
Here is another tidbit of information for those who may be using userid or some part of user info stored in Meteor.users database. When the page first loads the Meteor subscribe, going on in the background, may not be complete itself. Therefor when you try to connect to another database to query for that, it will not pull the information. This is because the Meteor.user() is still null itself;
The reason, like said above, is because the actual Meteor users collection has not gotten through pulling the data.
Simple way to deal with this.
Meteor.status().connected
This will return true or false, to let you know when the Meteor.user collection is ready. Then you can go on about your business.
I hope this helps someone, I was about to pull my hair out trying to figure out how to check the status. That was after figuring out the Meteor user collection itself was not loaded yet.
I am using a "2-step view", where I have a layout template (common for all pages) with yepnope's load (in the html head) of jQuery and some plugins. Something like:
yepnope(['/path/to/jquery.js', '/path/to/jquery.plugin-common.js']);
Sometimes I need another plugin, so within the inner template I do additional (in the html body):
yepnope('/path/to/jquery.plugin-additional.js');
Now that I need to do the actual js magic, can I safely do just:
yepnope({
complete: function(){...}
});
So, the questions are in fact two:
Is the complete callback fired upon the load completion of the global resources stack? So it's safe to "register" this complete callback anywhere assuming that all needed resources have been registered before?
Can I safely call yepnope just with the "complete" callback option? I mean, as long as I'm not "testing" anything and my resources have been registered already...
I have tried it and it worked, but I'm not fully aware if it's internals, so I just want to make sure that I'm not doing something wrong... Thanks in advance.
--
And one last thing. The manual under preload! says:
yepnope({
load: 'preload!jquery.1.5.0.js',
callback: function (url, result, key) {
window.jQuery; // undefined (but it's cached!);
}
});
Can you please explain what is this about? I am completely missing the point here...
I can help on the preload! question.
The idea of preload! is that yepnope will download the file but will not execute it.
It transfers the jQuery file, but it will still be undefined after callback is being called, as it was not injected as a script into the page.
In my opinion, you are doing this wrong. I'm surprised that it work, but maybe your scripts are loaded before the call of the "complete" function. I think you should do that:
yepnope({
load: ['/path/to/jquery.js', '/path/to/jquery.plugin-common.js']
callback: {
"jquery.js": function () {
console.log("jquery loaded!");
},
"jquery.plugin-common.js": function () {
console.log("plugin loaded!");
}
}
});
And for the additional plugin in the html body:
yepnope({
load: '/path/to/jquery.plugin-additional.js'
callback: function () {
$(document).ready(function(){
console.log("plugin-additional loaded!");
});
}
});
Of course, replace console.log() by your code related to each plugin that you can safely execute in this context.
for the last question, i can't say anything, because i didn't succeed to make preload! working, maybe it's buggy, maybe i didn't understand how it work...