Setting up global variable in SPA (Hot Towel) - global-variables

I want to have a global variable that is accessible to modify in any view in my application. I am wondering what this the best way to do so when using hot towel. Currently, I am declareing this variable in my shell.js and referencing this in subsequent views.
My shell.js returns the global variable. My other views have the shell defined at the top like define(['viewmodels/shell'], function(shell){} and I access the shell variable like shell.variablename. I am wondering if this is the best way of handling variables that need to be accessed by more than one view.

It can be done in many ways , either u create a config.js or any file or u can include the following code inside 'vm' object.
// config.js
define(function () {
var variableName= 'BlahBlah';
return {
debugEnabled: ko.observable(true),
variableName :variableName
};
});
// include this config.js in any javascript file
define(['folderName/config'],
function (config) {
var x= config.variableName;
}
This will work

Related

Meteor: How to access Template's Instance key in Blaze directly (without helper)?

Template.Demo.onCreated(function() {
this.test = 'Text';
});
How to access that template's instance test key in Blaze directly (without creating a helper function)?
{{Template.instance.test}} seems not to work (it was suggested here).
I don't believe this is possible with current versions of Blaze. That being said, you can simulate this by declaring a single global Template helper function, like:
Template.registerHelper('instance', function () {
return Template.instance();
});
Just define this once in a common client location, and you can then reference instance in any of your Template's. So you could reference your test variable like:
{{instance.test}}

How do I handle values that are dependent on the result of a helper?

So I have an Angular controller with a meteor helper method, as below.
function localeCtrl($scope, $reactive, $stateParams{
$reactive(this).attach($scope);
var self = this;
self.helpers({
locale: function(){ return Locales.findOne($stateParams.id)},
staff: function(){
// Load data from second collection based on current Locale.
// But how?
},
address: function(){
// Take self.location.address and massage it to provide
// google maps link. How?
}
tags: function(){
// Collect all unique instances of a given tag by
// iterating over the available locales.
// E. G. If 10 locales have the 'restaurant' tag, and 5
// more have the 'library' tag, I want an array of
// ['restaurant', 'library'] -- easy enough to do
// by iterating over the locales, but how do I do that
// reactively?
}
});
}
Unfortunately, I need to set additional properties based on the data fetched by locale(). I can't set them up when I initialize the controller because the value in locale() changes as data is fetched from the server. But I need access to the data in locale to, for example, create the google maps address, or fetch associated records. (They aren't imbedded in the locale document for reasons that I'm sure made sense at the time).
Edit:
Additionally, I'm using ground DB to store a local copy of the data for offline access, which makes life even more complicated.
Probably you best bet is to publish your collection using publishComposite which is implemented using the reywood:publish-composite package.
Add the package:
meteor add reywood:publish-composite
Now where you publish the Locales collection you would do something like this:
Meteor.publishComposite('locales', function() {
return {
find() {
//Put whatever you need in the query for locales
const query = {
_userId: this.userId
};
return Locales.find(query);
},
children: [{
find(locale) {
return Staff.find({ localeId: locale._id });
}
}]
};
});
Then in your controller before the helper you add this:
this.subscribe('locales');
Now you should be able to simply call the code like this:
this.helpers({
locale(){
return Locales.findOne(this.$stateParams.id);
}
});
And access it in the template like this:
locale.staff
Give that a try and let me know!

Where to put helper methods used in events for multiple Meteor templates

I know that I can access methods across files by omitting var, but what is the "best practices" project directory structure for defining helper methods that are used by template events across different templates.
For example, I have:
template1.js:
Template.template1.events({
'event': function () {
helper();
}
});
template2.js:
Template.template2.events({
'event': function () {
helper();
}
});
One problem with Meteor's "share code across files with globals" approach is that when you're looking at the file where a function is used, you don't know where the function is defined. I prefer to define a single global variable in each file which needs to export variables. That variable has the same name as the file, with an initial capital (or some other naming convention which identifies it as an "export object"). Exports are stored as properties of that object. So you might create a file named globalHelpers.js:
GlobalHelpers = {};
GlobalHelpers.helper = function () {
// ...
};
And then use it in other files with GlobalHelpers.helper(). If you look at this code later, you know to look in globalHelpers.js to find the helper function.
If a file exports a single class or collection then it's okay to just use that object as the export object. So instead of things.js with Things = {}; Things.Things = new Mongo.Collection... you can just do Things = new Mongo.Collection....
You might need to place the file in a lib directory so it loads before the other files.
Don't register it with Template.registerHelper unless you want to call it directly from templates with {{ }} calls.
I suggest defining such functions in /client/scripts/globalHelpers.js
Example:
Template.registerHelper('foo',function(arg1,arg2){
return arg1 + arg2;
});
Then you can use this function from anywhere by prefixing it with Blaze._globalHelpers.:
var result = Blaze._globalHelpers.foo(param1, param2);

How to use URL parameters using Meteorjs

How can I use URL parameters with meteor.
The URL could look like this: http://my-meteor.example.com:3000?task_name=abcd1234
I want to use the 'task_name' (abcd1234) in the mongodb query in the meteor app.
eg.
Template.task_app.tasks = function () {
return Tasks.find({task_name: task_name});
};
Thanks.
You are probably going to want to use a router to take care of paths and rendering certain templates for different paths. The iron-router package is the best one available for that. If you aren't using it already I would highly recommend it.
Once you are using iron-router, getting the query strings and url parameters is made very simple. You can see the section of the documentation here: https://github.com/iron-meteor/iron-router/blob/devel/Guide.md#route-parameters
For the example you gave the route would look something like this:
Router.map(function () {
this.route('home', {
path: '/',
template: 'task_app'
data: function () {
// the data function is an example where this.params is available
// we can access params using this.params
// see the below paths that would match this route
var params = this.params;
// we can access query string params using this.params.query
var queryStringParams = this.params.query;
// query params are added to the 'query' object on this.params.
// given a browser path of: '/?task_name=abcd1234
// this.params.query.task_name => 'abcd1234'
return Tasks.findOne({task_name: this.params.query.task_name});
}
});
});
This would create a route which would render the 'task_app' template with a data context of the first task which matches the task name.
You can also access the url parameters and other route information from template helpers or other functions using Router.current() to get the current route. So for example in a helper you might use Router.current().params.query.task_name to get the current task name. Router.current() is a reactive elements so if it is used within the reactive computation the computation will re-run when any changes are made to the route.

pre-populating app settings witha meteor collection

I'm trying to get my head around the way meteor work.
I'm building a site prototype and I'd like to pre-populate it with data like site.title, site.logo, site.contact.number etc...
I've created a Settings collection:
Settings = new Meteor.Collection('settings');
Settings.insert(
{
logo: 'test logo',
contact: {
human: '01 01 01 01 01',
machine: '0101010101'
}
}
)
is it possible in the html markup to then retrieve this data across templates, as Meteor is subscribed to the collection?
I'm trying to do things like:
{{settings.logo}}
<a href="{{settings.contact.machine}}" class="logo url" rel="me" {{settings.contact.human}}</a>
Meteor is running on auto publish at the moment so I'm not sure if I need to do something in my main.js file. Can Meteor access all values automatically? at the moment it prints [object,object]
update
I've created a settings.json file:
{
"public" : {
"logo" : "my fancy company name",
"contact" : {
"human" : "01 01 01 01 01 ",
"machine" : "0044101010101"
}
}
}
Then I changed my Handlebars.registerHelper to
Handlebars.registerHelper('view', function(){
return Meteor.settings.public
});
I can now access all of the settings without creating a Collection for them, much more easily.
cheers
Your approach is wrong on several levels.
The handlebar expression {{settings.contact.machine}} will insert *currentContextObject*.settings.contact.machine into the HTML, where *currentContextObject* is the template's data context.
What is your template's data context? I don't know but it doesn't matter because settings.contact.machine won't make sense either way. Settings is a collection of documents but you are trying to use it as if it were a single object.
What would work in JS is Settings.findOne().contact.machine. To access this setting across templates you would need to create a global template helper like e.g.:
if (Meteor.isClient) {
Handlebars.registerHelper("getMachineContact", function() {
return Settings.findOne().contact.machine;
});
}
Then you could use {{getMachineContact}} in your HTML.
Still this solution wouldn't be nice and you should probably be using Meteor.settings instead of a Settings collection for solving your use case.
Similar to here you could then create a global template helper that returns arbitrary values from Meteor.settings given their path, meaning you could for example write {{getSetting "contact.machine"}}. This approach would involve converting a string in dot notation ("contact.machine") into an object reference so this question might be useful.

Resources