I'm quite new to Meteor and relatively new to JS as well.
The code i'm using is:
server/methods.es6
var cheerio = Meteor.npmRequire('cheerio');
/*****************************************************************************/
/* Server Only Methods */
/*****************************************************************************/
Meteor.methods({
/*
* Example:
*
* '/app/items/insert': function (item) {
* }
*/
player: function () {
const url = 'http://cdn.content.easports.com/fifa/fltOnlineAssets/C74DDF38-0B11-49b0-B199-2E2A11D1CC13/2014/fut/items/web/165434.json';
const response = Meteor.http.get(url);
return response;
}
});
client/templates/cars/cars_list.es6
Meteor.call('player', function (err, res) {
if (err) console.log(err);
console.log(JSON.parse(res.content));
Session.set('player', JSON.parse(res.content));
});
/*****************************************************************************/
/* CarsList: Event Handlers */
/*****************************************************************************/
Template.CarsList.events({
});
/*****************************************************************************/
/* CarsList: Helpers */
/*****************************************************************************/
Template.CarsList.helpers({
cars: function () {
return Cars.find();
},
player: function () {
return Session.get('player');
}
});
client/templates/cars/cars_list.html
<template name="CarsList">
<h1>Cars List</h1>
{{ player.Item.FirstName }}
<table class="table table-hover">
<thead>
<tr>
<th>Brand</th>
<th>Model</th>
<th>Fuel Type</th>
<th>Body Style</th>
<th>Top Speed</th>
<th>Power</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
{{# each cars }}
{{> car }}
{{/ each }}
</tbody>
</table>
</template>
Most of it is just test code to try and do HTTP requests.
When i remove all the code related to player everything is instant. When the player code is there the page loads instantly but the cars data doesn't show until the HTTP request for player is resolved. Is there a way to put the HTTP request in the background while everything else does what it used to do?
Also is there a way to loop HTTP requests and show the data as i receive it back?
I would advise you to put you method code in your both folder. That way, latency compensation won't be affected and your user interface will update as fast as it is supposed to.
If you need to hide some of the code from the client, you can put it in both client and server folders. I have not tested this, but I assume that if the result of the client call is different (i.e. he messed it up with the console) you will rollback its data to the server one.
This way, you simulate the method results from the server while it has not come back yet. However, keep in mind that whatever setup you use, you end up having to wait for the website data to go on, whether it is on client or server.
If you call your data like that, I think it does not only stop your mongo data, but also your js functions execution (the event loop). I might be wrong (newbie here too)
Maybe you should read about fiber and future, and the async calls. It seems to me it is the way to go.
Good luck!
Related
I wanted to display all the user information in a tabular format as a part of an admin page. I used meteor accounts ui package for the same.
The HTML code is:
{{#each userList}}
<tbody>
<tr>
<th scope="row">*</th>
<td>{{infofullname}}</td>
<td>{{infosurname}}</td>
<td>{{infoemail}}</td>
</tr>
</tbody>
{{/each}}
The problem is that the information for the current user is getting displayed and not all the enrolled users. The iteration does happen but for the current logged in user. Also the email address is not getting displayed.
The helper code is:
Template.students.helpers({
userList: function(){
return Meteor.users.find({});
},
infofullname: function(){
return Meteor.user().profile.fullname;
},
infosurname: function(){
return Meteor.user().profile.surname;
},
infoemails: function(){
return Meteor.user().emails.[0].address;
}
});
Im facing the following problems:
1) The email address is not getting displayed.
2)The information of all the users is not getting displayed.
Thank You.
Publish all users with the following on the server:
Meteor.publish('allUsers',function(){
return Meteor.users.find({},{fields: {emails: 1, profile: 1}});
this.ready();
});
Then subscribe on the client with:
Meteor.subscribe('allUsers');
Your helpers will need some slight modifications as #Sudhanshu suggested however since you're looping over a cursor of users you can take advantage of this being an individual user object inside the loop.
Template.students.helpers({
userList() {
return Meteor.users.find({});
},
infofullname() {
return this.profile.fullname;
},
infosurname() {
return this.profile.surname;
},
infoemails: function(){
return this.emails.[0].address;
}
});
You can also access nested properties directly in blaze, avoiding the need for three of your helpers, ex:
{{#each userList}}
<tbody>
<tr>
<th scope="row">*</th>
<td>{{profile.fullname}}</td>
<td>{{profile.surname}}</td>
<td>{{emails.[0].address}}</td>
</tr>
</tbody>
{{/each}}
Multiple things are wrong:
Meteor.users() will give you multiple users only if you publish them (or you use autopublish).
Meteor.user() will always give you only the currently logged in user. So all your helpers will not work as per your plan. Modify them to use Meteor.users.findOne({_id: id)}). You can always use helpers with parameters.
Meteor publishes only the profile by default and not the emails. So you will have to publish the emails field in your publication.
I am trying to get data from a collection in meteor and using a helper passing it to a template.
Here is my code in collection:
Meteor.publish('displayCustomers', function tasksPublication() {
return Customers.find();
});
Below code in template JS file
Template.customerlist.onCreated(function() {
Meteor.subscribe('displayCustomers');
});
Template.customerlist.helpers({
displayCustomers :function(){
console.log(Customers.find({}));
return Customers.find({});
},
});
Template:
<template name="customerlist">
<h1>All registered users</h1>
{{#each displayCustomers}}
{{fname}}
{{/each}}
</template>
It is only displaying HTML content i.e. <h1>All registered users</h1>
Check that your publication is returning values to the client with this MiniMongo chrome extension
Check to make sure Customers is defined on the server and that your publish block is running only on the server.
Also I would toss a debugger into your onCreated block to make sure that your subscribe is being initialized.
Other than that, your code looks fine. I would try installing MeteorToys Mongol for client pub/sub debugging. https://atmospherejs.com/msavin/mongol
You need to actually fetch documents in your template :
Template.customerlist.helpers({
displayCustomers :function(){
return Customers.find().fetch(); //will return an array with all published documents
},
});
I am struggling to figure out the basic pattern for populating a template with data from a call to an external API in Meteor.
These are the elements in play
A fresh Meteor project, created by running meteor create monkeyproject
The URL of an external API that returns a JSON array. Let's say it's example.com/api/getmonkeys. It returns an array of monkeys, each with a different name.
A Handlebar template called monkeyTemplate with an {{#each}} loop. Let's say it's this:
<template name="monkeyTemplate">
{{# each monkeys}}
One of our monkeys is named {{name}}. <br>
{{/each}}
<input type="button" id="reload" value="Reload monkeys" />
</template>
What I want to happen
When the page loads fill monkeyTemplate with monkeys from our external URL.
When the user clicks the button, call the external URL again to reload the monkeys.
The question
What is a standard pattern for doing the above in Meteor? At the risk of cluttering up the question, I'll include some starting points, as I understand them.
We can populate the template with whatever we return from our Template.monkeyTemplate.monkeys function. How do we fill it with content from an external URL, given that the page will load before the external request is finished?
We can get our JSON by using Meteor.HTTP.call("GET", "http://example.com/api/getmonkeys", callback ). Where do we put this request, and what do we put into our callback function in this situation?
We can control what happens on the server side and what happens on the client side by using the Meteor.isServer/Meteor.isClient conditions, or by putting our code into files called client and server folders. What code needs to be on the server side vs. the client side?
We determine what happens when the button is clicked by attaching a function to Template.monkeyTemplate.events['click #reload']. What goes into our callback function in this situation?
I will refrain from cluttering up the question with my crappy code. I am not looking for anyone to write or rewrite an application for me—I am just looking for the guidelines, standard patterns, best practices, and gotchas. Hopefully this will be instructive to other beginners as well.
I'm not sure if this is the "standard" template, but it serves the purpose pretty well.
Set up two data helpers for the template, monkeys and loading. First one will display the actual data once it's fetched, the latter will be responsible for notifying user that the data is not yet fetched.
Set up a dependency for these helpers.
In created function of the template, set loading helper to true and fetch the data with HTTP call.
In the callback, set the template data and fire the dependency.
html
<template name="monkeys">
{{#if loading}}
<div>Loading...</div>
{{/if}}
{{#if error}}
<div>Error!</div>
{{/if}}
{{#each monkeys}}
<div>{{name}}</div>
{{/each}}
<div><button class="monkeys-reloadMonkeys">Reload</button></div>
</template>
js
var array = null;
var dep = new Deps.Dependency();
Template.monkeys.created = function() {
reloadMonkeys();
};
Template.monkeys.events({
'click .monkeys-reloadButton': function(e,t) {
reloadMonkeys();
};
});
var reloadMonkeys = function() {
array = null;
dep.changed();
HTTP.get('http://example.com/api/getmonkeys', function(error, result) {
if(!error && result) {
array = result;
} else {
array = 0;
}
dep.changed();
});
};
Template.monkeys.monkeys = function() {
dep.depend();
return array ? array : [];
};
Template.monkeys.loading = function() {
dep.depend();
return array === null;
};
Template.monkeys.error = function() {
dep.depend();
return array === 0;
};
I have an app that subscribes to 4 collections (the collections are very small 1 to 20 records each). But the amount of time it takes to load these collections is huge.
One of them is just 13 records, and it takes several seconds to load its template. Is it normal? (I'm still testing on meteor servers)
this is a sample of the code :
Meteor.subscribe('trackedUser', function() {
console.log('finished fetching trackedUser');
Template.users.rendered = function() {
/*handlign of the template*/
console.log('users template rendered');
}
});
/*observe geolocation after it is all fetched*/
Meteor.subscribe('geolocation', function() {
console.log('finished fetching location');
/* Obseve the Collection geolocation and trigger event when item inserted or removed */
query = Geolocation.find({});
query.observeChanges({
added: function(id) {
addMarkerToMap(id);
window.map.fitBounds(group.getBounds());
return;
}
});
});
});
And this is my template
<template name="users">
<ul id="item-list">
{{#each trackedUser}}
<li id="{{_id}}">
<input type="checkbox" checked />
<span><select name="colorpicker">
{{#each color}}
<option value="{{mColorCode}}" {{selected ../mColor mColorCode}}>{{mColorName}}</option>
{{/each}}
</select>
</span>
<img width="40" src="data:image/png;base64,{{mImage}}" />
<span class="name">{{mUsername}}</span>
<p><span class="description">{{mDescription}}</span></p>
</li>
{{/each}}
</ul>
</template>
Thanks
I was able to solve this issue by adding a condition to the definition of the template content that is false while loading the page, i.e., doing the initial sync, and only activating that content when it was loaded.
Before (10s page load for 300 records being published by the server):
Template.itemlist.items = function () {
return Item.find({type: 'car'},
{sort: {start: -1},
limit: 30});
};
To (2s page load for 3000 records published by the server):
Template.itemlist.items = function () {
if (Session.get("active")) {
return Item.find({type: 'car'},
{sort: {start: -1},
limit: 30});
} else {
return [];
}
};
To "activate" the session only once the data was loaded, I added:
Deps.autorun(function () {
Meteor.subscribe("Item",
{
onReady: function() {
Session.set("active", true);
}
});
});
I recently had to diagnose a performance issue with a meteor app and found that it wasn't the rendering of the template that was slow, but rather the transferring of data between the server and the browser.
You can use the Chrome developer tools to diagnose the issue.
Open the tool and make sure it's profiling Network traffic
Load your site
Examine the network traffic. Did it take a long time for the data to finish coming to your browser?
If the data is taking a long time to finish coming to your browser then you can dive deeper into the websocket traffic:
Filter for websocket traffic (bottom of the network tab)
Select the websocket request to view the frames
Examine the information in the frames. Is it a lot?
You may find (as I did) that you are transferring a lot of information to the browser that isn't needed to render the templates.
In that case, make sure you've disabled autopublish and then publish just the data you need by using the field specifier.
I have a collection published on the server and auto-subscribed on the client. I'd like to set the 'selected' item on the session and have the template update to display only the selected item, but it seems this can only be done with a roundtrip to the server (which is totally unnecessary).
Common:
var Missions = new Meteor.Collection('missions');
Client:
Template.missionList.missions = function() {
var currMission = Session.get('selectedMission');
var searchMission = {};
if(currMission)
{
searchMission['_id'] = currMission;
}
return Missions.find(searchMission);
};
Template.missionList.events({
'click div.mission': function (e, t) {
Session.set('selectedMission',
this._id == Session.get('selectedMission') ? null : this._id
);
}
});
Template.mission.isSelected = function() {
return this._id == Session.get('selectedMission');
};
Meteor.autosubscribe(function () {
Meteor.subscribe("missions");
});
Server:
Meteor.publish('missions', function() {
// there are really some filters here, but removed for simplicity
return Missions.find();
});
Template:
<template name="missionList">
<div class="missionList">
{{#each missions}}
{{> mission}}
{{/each}}
</div>
</template>
<template name="mission">
<div class="mission{{#if isSelected}} selected{{/if}}">details</div>
</template>
My requirement is for the Missions.find() in Template.missionList.missions to filter the client-side cached results, rather than to re-request from the server, but I can't seem to find a flag or settings to allow me to tell minimongo to only use the currently available data.
I'm also not entirely sure if this is what I should be doing, I started out just using jQuery to hide the non-selected missions but getting my head round Meteor and it seems a natural fit to use the data and reactivity to drive selection/local-filtering.
Is there any way the roundtrip can be avoided or am I just using it wrong?
By setting up a publish / subscribe relationship, you are creating a simplified form of database replication. Minimongo will have a copy of the data locally and execute the find() locally without a server roundtrip. If you are seeing network activity or calls to the server code, it is because meteor is regularly working behind the scenes to keep the subscription in sync with the server, not for your specific find.
This also means you have to wary of sending too much data to the client, so your server side publish function may want to filter by the specific fields needed by client, in addition to existing your selection criteria.