Find on meteor client don't work - javascript

I'm trying to do a pretty basic example using meteor js.
In my lib folder (shared by client and server) i have the following code
if (typeof hair === 'undefined') {
hair = {};
}
if (!hair.dao) {
hair.dao = {};
}
hair.dao.store = (function() {
return new Meteor.Collection('store');
})();
In folder server/libs i have this code
Meteor.startup(function() {
console.log(hair.dao.store.find().fetch());
});
(Which log one element)
In my client/libs folder i have this code
var cursorStores;
cursorStores = hair.dao.store.find();
console.log(cursorStores.fetch());
(Which logs no element)
It used to work, but now it stops.
Just to be clear i'm running on windows, and i removed and added again the autopublish package.

The data probably hasn't reached the client yet when you do that find. Try wrapping those 3 lines of client code in a Deps.autorun

I think find needs to take an argument. See http://docs.meteor.com/#find
If you are wanting the first element there are other ways of getting it. http://docs.meteor.com/
Try find({}) with empty curly braces

Related

I cannot access the variable in the other script. (Module.exports don't work everywhere)

I have been having issues with module.exports.
I have 2 Scripts that use Discord.js, and i need to have a SetTimeout() variable that is common to both scripts to be able to use ClearTimeout() from each of them.
I tried to use:
//first script
var foo = 20;
module.exports.foo = foo;
//Second Script
var exp = require('./firstscript');
console.log(exp.foo);
This was a test, to see if i was doing it the wrong way, with a simple variable instead of my SetTimeout().
The test worked fine when i ran new scripts with the node command but with npm start on my 2 original scripts it returned 'undefined' while having the same syntax.
In every script is already a module.exports for the Discord.js event class like 'Ready' for exemple.
I'm running this bit of code outside the main module.exports at the top where the const are declared.
I wonder if this is causing my issue.
example:
//the code i'm talking about is here.
module.exports = class ReadyEvent extends BaseEvent {
constructor() {
super('ready');
}
async run(client) {
Thanks for your help. Ask me for clarification if needed.
EDIT:
I looked up on the internet to see if it was an issue with the module.export that was already present on the script. And it was.
Apparently you cannot have several module.export in a script if each one of them doesn't specify a variable:
//this doesn't work
module.exports.value = value;
module.exports = value2;
//this works
module.exports.value = value;
module.exportd.value2 = value2;
My problem was that the one already present was used by the 'discord.js compiler' to register every command so i couldn't modify it without breaking the bot.
I decided to put my timer in a new script named GlobalVars and it worked Perfectly fine.
I'm Satisfied that it works now. For me the issue is fixed but i would love to know if it is possible to export a variable WITH the discord.js module.exports syntax included.
From your Second Script variable, its seems to be requiring a folder and not a file, and I don't think folders are allowed.
Assuming you are requiring a script and not a folder:
First Mistake: When requiring, inside the brackets you must have quotation marks ("") or ('').
If it is a folder, add a / next to ./firstscript and assign it to the file you want to refer to.
var exp = require('./firstscript/THE_INTENDED_FILE');
...If firstscript is a json file:
var exp = require('./firstscript.json');
Extracting Variables from file
// Option 1:
console.log(exp.foo);
// Option 2:
const extract = exp.foo
console.log(extract);

Rails 5/6: How to include JS functions with webpacker?

I am trying to update a Rails 3 app to Rails 6 and I have problems with the now default webpacker since my Javascript functions are not accessible.
I get: ReferenceError: Can't find variable: functionName for all js function triggers.
What I did is:
create an app_directory in /app/javascript
copied my development javascript file into the app_directory and renamed it to index.js
added console.log('Hello World from Webpacker'); to index.js
added import "app_directory"; to /app/javascript/packs/application.js
added to /config/initializers/content_security_policy.rb:
Rails.application.config.content_security_policy do |policy|
policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
end
I get 'Hello World from Webpacker' logged to console, but when trying to access a simple JS function through <div id="x" onclick="functionX()"></div> in the browser I get the reference error.
I understand that the asset pipeline has been substituted by webpacker, which should be great for including modules, but how should I include simple JS functions? What am I missing?
Thanks in advance?
For instructions on moving from the old asset pipeline to the new webpacker way of doing things, you can see here:
https://www.calleerlandsson.com/replacing-sprockets-with-webpacker-for-javascript-in-rails-5-2/
This is a howto for moving from the asset pipeline to webpacker in Rails 5.2, and it gives you an idea of how things are different in Rails 6 now that webpacker is the default for javascript. In particular:
Now it’s time to move all of your application JavaScript code from
app/assets/javascripts/ to app/javascript/.
To include them in the JavaScript pack, make sure to require them in
app/javascript/pack/application.js:
require('your_js_file')
So, create a file in app/javascript/hello.js like this:
console.log("Hello from hello.js");
Then, in app/javascript/packs/application.js, add this line:
require("hello")
(note that the extension isn't needed)
Now, you can load up a page with the browser console open and see the "Hello!" message in the console. Just add whatever you need in the app/javascript directory, or better yet create subdirectories to keep your code organized.
More information:
This question is cursed. The formerly accepted answer is not just wrong but grotesquely wrong, and the most upvoted answer is still missing the mark by a country mile.
anode84 above is still trying to do things the old way, and webpacker will get in your way if you try that. You have to completely change the way you do javascript and think about javascript when you move to webpacker. There is no "scoping issue". When you put code in a web pack it's self-contained and you use import/export to share code between files. Nothing is global by default.
I get why this is frustrating. You're probably like me, and accustomed to declaring a function in a javascript file and then calling it in your HTML file. Or just throwing some javascript at the end of your HTML file. I have been doing web programming since 1994 (not a typo), so I've seen everything evolve multiple times. Javascript has evolved. You have to learn the new way of doing things.
If you want to add an action to a form or whatever, you can create a file in app/javascript that does what you want. To get data to it, you can use data attributes, hidden fields, etc. If the field doesn't exist, then the code doesn't run.
Here's an example that you might find useful. I use this for showing a popup if a form has a Google reCAPTCHA and the user hasn't checked the box at the time of form submission:
// For any form, on submit find out if there's a recaptcha
// field on the form, and if so, make sure the recaptcha
// was completed before submission.
document.addEventListener("turbolinks:load", function() {
document.querySelectorAll('form').forEach(function(form) {
form.addEventListener('submit', function(event) {
const response_field = document.getElementById('g-recaptcha-response');
// This ensures that the response field is part of the form
if (response_field && form.compareDocumentPosition(response_field) & 16) {
if (response_field.value == '') {
alert("Please verify that you are not a robot.");
event.preventDefault();
event.stopPropagation();
return false;
}
}
});
});
});
Note that this is self-contained. It does not rely on any other modules and nothing else relies on it. You simply require it in your pack(s) and it will watch all form submissions.
Here's one more example of loading a google map with a geojson overlay when the page is loaded:
document.addEventListener("turbolinks:load", function() {
document.querySelectorAll('.shuttle-route-version-map').forEach(function(map_div) {
let shuttle_route_version_id = map_div.dataset.shuttleRouteVersionId;
let geojson_field = document.querySelector(`input[type=hidden][name="geojson[${shuttle_route_version_id}]"]`);
var map = null;
let center = {lat: 36.1638726, lng: -86.7742864};
map = new google.maps.Map(map_div, {
zoom: 15.18,
center: center
});
map.data.addGeoJson(JSON.parse(geojson_field.value));
var bounds = new google.maps.LatLngBounds();
map.data.forEach(function(data_feature) {
let geom = data_feature.getGeometry();
geom.forEachLatLng(function(latlng) {
bounds.extend(latlng);
});
});
map.setCenter(bounds.getCenter());
map.fitBounds(bounds);
});
});
When the page loads, I look for divs with the class "shuttle-route-version-map". For each one that I find, the data attribute "shuttleRouteVersionId" (data-shuttle-route-version-id) contains the ID of the route. I have stored the geojson in a hidden field that can be easily queried given that ID, and I then initialize the map, add the geojson, and then set the map center and bounds based on that data. Again, it's self-contained except for the Google Maps functionality.
You can also learn how to use import/export to share code, and that's really powerful.
So, one more that shows how to use import/export. Here's a simple piece of code that sets up a "watcher" to watch your location:
var driver_position_watch_id = null;
export const watch_position = function(logging_callback) {
var last_timestamp = null;
function success(pos) {
if (pos.timestamp != last_timestamp) {
logging_callback(pos);
}
last_timestamp = pos.timestamp;
}
function error(err) {
console.log('Error: ' + err.code + ': ' + err.message);
if (err.code == 3) {
// timeout, let's try again in a second
setTimeout(start_watching, 1000);
}
}
let options = {
enableHighAccuracy: true,
timeout: 15000,
maximumAge: 14500
};
function start_watching() {
if (driver_position_watch_id) stop_watching_position();
driver_position_watch_id = navigator.geolocation.watchPosition(success, error, options);
console.log("Start watching location updates: " + driver_position_watch_id);
}
start_watching();
}
export const stop_watching_position = function() {
if (driver_position_watch_id) {
console.log("Stopped watching location updates: " + driver_position_watch_id);
navigator.geolocation.clearWatch(driver_position_watch_id);
driver_position_watch_id = null;
}
}
That exports two functions: "watch_position" and "stop_watching_position". To use it, you import those functions in another file.
import { watch_position, stop_watching_position } from 'watch_location';
document.addEventListener("turbolinks:load", function() {
let lat_input = document.getElementById('driver_location_check_latitude');
let long_input = document.getElementById('driver_location_check_longitude');
if (lat_input && long_input) {
watch_position(function(pos) {
lat_input.value = pos.coords.latitude;
long_input.value = pos.coords.longitude;
});
}
});
When the page loads, we look for fields called "driver_location_check_latitude" and "driver_location_check_longitude". If they exist, we set up a watcher with a callback, and the callback fills in those fields with the latitude and longitude when they change. This is how to share code between modules.
So, again, this is a very different way of doing things. Your code is cleaner and more predictable when modularized and organized properly.
This is the future, so fighting it (and setting "window.function_name" is fighting it) will get you nowhere.
Looking at how webpacker "packs" js files and functions:
/***/ "./app/javascript/dashboard/project.js":
/*! no static exports found */
/***/ (function(module, exports) {
function myFunction() {...}
So webpacker stores these functions within another function, making them inaccessible. Not sure why that is, or how to work around it properly.
There IS a workaround, though. You can:
1) change the function signatures from:
function myFunction() { ... }
to:
window.myFunction = function() { ... }
2) keep the function signatures as is, but you would still need to add a reference to them as shown here:
window.myFunction = myFunction
This will make your functions globally accessible from the "window" object.
Replace the code in your custom java Script file
from
function function_name() {// body //}
to
window.function_name = function() {// body //}
From the official rails app guide:
Where to Stick Your JavaScript
Whether you use the Rails asset
pipeline or add a tag directly to a view, you have to make a
choice about where to put any local JavaScript file.
We have a choice of three locations for a local JavaScript file:
The app/assets/javascripts folder,the lib/assets/javascripts folder and the vendor/assets/javascripts folder
Here are guidelines for selecting
a location for your scripts:
Use app/assets/javascripts for JavaScript you create for your
application.
Use lib/assets/javascripts for scripts that are shared by many
applications (but use a gem if you can).
Use vendor/assets/javascripts for copies of jQuery plugins, etc., from
other developers. In the simplest case, when all your JavaScript files
are in the app/assets/javascripts folder, there’s nothing more you
need to do.
Add JavaScript files anywhere else and you will need to understand how
to modify a manifest file.
More reading:
http://railsapps.github.io/rails-javascript-include-external.html

NodeJS: Single object with all requires, or "standard" paths in code?

So, I'm a big fan of creating global namespaces in javascript. For example, if my app is named Xyz I normally have an object XYZ which I fill with properties and nested objects, for an example:
XYZ.Resources.ErrorMessage // = "An error while making request, please try again"
XYZ.DAL.City // = { getAll: function() { ... }, getById: function(id) { .. } }
XYZ.ViewModels.City // = { .... }
XYZ.Models.City // = { .... }
I sort of picked this up while working on a project with Knockout, and I really like it because there are no wild references to some objects declare in god-knows-where. Everything is in one place.
Now. This is ok for front-end, however, I'm currently developing a basic skeleton for a project which will start in a month, and it uses Node.
What I wanted was, instead of all the requires in .js files, I'd have a single object ('XYZ') which would hold all requires in one place. For example:
Instead of:
// route.js file
var cityModel = require('./models/city');
var cityService = require('./services/city');
app.get('/city', function() { ...........});
I would make an object:
XYZ.Models.City = require('./models/city');
XYZ.DAL.City = require('./services/city');
And use it like:
// route.js file
var cityModel = XYZ.Models.City;
var cityService = XYZ.DAL.City;
app.get('/city', function() { ...........});
I don't really have in-depth knowledge but all of the requires get cached and are served, if cached, from memory so re-requiring in multiple files isn't a problem.
Is this an ok workflow, or should I just stick to the standard procedure of referencing dependencies?
edit: I forgot to say, would this sort-of-factory pattern block the main thread, or delay the starting of the server? I just need to know what are the downsides... I don't mind the requires in code, but I just renamed a single folder and had to go through five files to change the paths... Which is really inconvenient.
I think that's a bad idea, because you are going to serve a ton of modules every single time, and you may not need them always. Your namespaced object will get quite monstrous. require will check the module cache first, so I'd use standard requires for each request / script that you need on the server.

Sharing Code between Node.js and the browser

I'm working on a project that uses Node.js. I'm familiar with JavaScript, but not great. As part of that, I've run into a challenge that I'm not sure how to overcome.
I need to share some code on the server (Node.js) and my client-side (browser) app. I want to be able to access this code by typing the following:
myCompany.myProject.myFunction(someValue);
or just
myProject.myFunction(someValue);
In an attempt to do this, I have the following:
'use strict';
var myCompany = myCompany || {};
var myProject = myCompany.myProject || {};
myProject.myFunction= function(someValue) {
console.log(someValue);
};
Inside of myFunction, I want to one thing if I'm running on the server (Node.js) and something different if I'm running in the browser. However, I'm not sure how to do that. I reviewed this post and this SO question, yet I still don't understand it.
Thank you for your help!
You need something like this:
function someFunctionName() {
// Common functional
if (typeof module !== 'undefined' && module.exports) {
// Do something only in Node.JS
} else {
// Do something else in the browser
}
// Common functional
}

Read file with fs.readFileSync and eval contents...which scope have the functions? How to access?

I recently tried to import a file into my existing node.js project. I know this should be written with a module but i include my external javascript file like this:
eval(fs.readFileSync('public/templates/simple.js')+'')
The contents of simple.js looks like this:
if (typeof examples == 'undefined') { var examples = {}; }
if (typeof examples.simple == 'undefined') { examples.simple = {}; }
examples.simple.helloWorld = function(opt_data, opt_sb) {
var output = opt_sb || new soy.StringBuilder();
output.append('Hello world!');
return opt_sb ? '' : output.toString();
};
(Yes, google closure templates).
I can now call the template file using:
examples.simple.helloWorld();
Everything is working like expected. However I'm not able to figure out what the scope of these functions is and where I could possibly access the examples object.
Everything is running in a node.js 0.8 server and like I said its working...I just dont quite know why?
Thanks for clarification.
eval() puts variables into the local scope of the place where you called it.
It's as if the eval() was replaced by the code in the string argument.
I suggest to change the content of the files to:
(function() {
...
return examples;
})();
That way, you can say:
var result = eval(file);
and it will be obvious where everything is/ends up.
Note: eval() is a huge security risk; make sure you read only from trusted sources.

Categories