I have a meteor 1.1.0.3 app, with the following code:
//Publishing:
Meteor.publish("movies", function () {
var user = Meteor.users.findOne({_id: this.userId});
return movies.find({"imdbRating": {$gte: user.imdb_rating}});
});
//Subscribing:
my_movies = Meteor.subscribe('movies', function() {
return movies.find();
});
Router.route('/', function () {
this.render('home', {
data: {"movies": movies.find()}
});
});
//Rendering:
<table class="table table-bordered table-striped">
...
<tbody>
{{#each movies}}
...
{{/each}}
</tbody>
</table>
In that way, my movies are not updated when there are new ones in the database. How can I make the table change the movies that are shown every time the publish query return different results?
Template Level Subscription I think should do it with an autorun block to watch for the database changes. https://www.discovermeteor.com/blog/template-level-subscriptions/
Related
I am trying to fetch data stored in parse.com collection. I am using Parse Javascript SDK to call the service asynchronously as following:
ctrl.factory('TLDs', function($q){
var query = new Parse.Query(Fahras)// Fahras is the Parse Object initialized earlier in code
query.equalTo("type", "Domain")
var myCollection = query.collection()
return {
fetchDomains: function(){
var defer = $q.defer();
myCollection.fetch({
success : function(results) {
defer.resolve(results.modles);
console.info(results.models)
},
error : function(aError) {
defer.reject(aError);
}
});
console.info(defer.promise)
return defer.promise;
}
}
}) // end of factory topDomains
I have a simple table to show the fetched data
<div id="showdomainshere"> {{domains}}</div>
<table id="domains_table" class="table table-hover">
<thead>
<tr>
<th>Domain</th>
<th>Code</th>
<th>Subjects</th>
<th>Instances</th>
</tr>
</thead>
<tbody id="table_body">
<form id="edit_row" class="form-inline">
<tr ng-repeat="item in domains">
<td><span>{{item.attributes.arTitle}}</span>
</td>
<td><span>{{item.attributes.domainCode}}</span>
</td>
<td><span>{{subclasses}}</span>
</td>
<td><span>{{instances}}</span>
</td>
</tr>
</form>
</tbody>
</table>
</div> <!-- end of main div -->
And hereunder the controller I ma using to render the view:
ctrl.controller('Home', ['$scope','TLDs',function($scope, TLDs) {
$scope.domains = TLDs.fetchDomains()
}])
Using console.info I can see that the result is fetched and I can go through the array of returned models as expected. Problem is that $scope.domains never been updated and as a result the table never been rendered
Fortunately I am able to figure it out.
The controller should be like:
ctrl.controller('Home', ['$scope','TLDs',function($scope, TLDs) {
TLDs.fetchDomains().then(function(data){
$scope.domains = data
})
}
While the factory itself should be like:
ctrl.factory('TLDs', function($q){
var query = new Parse.Query(Fahras)
query.equalTo("type", "Domain")
var myCollection = query.collection()
return {
fetchDomains: function(){
var defer = $q.defer();
myCollection.fetch({
success : function(results) {
defer.resolve(results.models)
return results.models
},
error : function(aError) {
defer.reject(aError)
}
})
return defer.promise;
}
} }) // end of factory
I am making simple application where user can add some data in the website. Every time, when user adds new 'name' I want display the latest name automatically for every connected users.
I am not sure if my implementation of Template.names.name is a good idea, maybe I should use subscribe instead?
Here is my code:
<template name="names">
<p>What is your name ?</p>
<input type="text" id="newName"/>
<input type="button" id="nameSubmit" value="add new"/>
<p>Your name: {{name}}</p>
</template>
if (Meteor.isClient) {
Template.names.name({
'click input#nameSubmit': function () {
Meteor.call('newName', document.getElementById("newName").value);
}
});
Template.names.name = function () {
var obj = Names.find({}, {sort: {"date": -1}}).fetch()[0];
return obj.name;
};
}
if (Meteor.isServer) {
newName: function (doc) {
var id = Names.insert({
'name': doc,
'date': new Date()
});
return id;
}
}
I use meteorjs version 0.8.1.1.
The only thing I see inherently wrong with your code is your method.. To define methods you can use with Meteor.call you have you create them with a call to Meteor.methods
Meteor.methods({
newName: function (name) {
Names.insert({
'name': doc,
'date': new Date()
});
}
});
Another couple notes.. The Method should be defined in shared space, not just on the server unless there is some specific reason. That why it will be simulated on the client and produce proper latency compensation.
Also in your Template.names.name you can return the result of a findOne instead of using a fetch() on the cursor.
Template.names.name = function () {
return Names.findOne({}, {sort: {"date": -1}}).name;
};
I'm new to Meteor.
Trying to render items from collection but Meteor.renderList(observable, docFunc, [elseFunc]) alway go to elseFunc.
this.ComponentViewOrdersFlow = Backbone.View.extend({
template: null,
initialize: function() {
var frag;
Template.ordersFlow.events = {
"click a": function(e) {
return App.router.aReplace(e);
}
};
this.template = Meteor.render(function() {
return Template.ordersFlow();
});
console.log(Colors);
frag = Meteor.renderList(
Colors.find(),
function(color) {
console.log(color);
},
function() {
console.log('else consdition');
}
);
},
render: function() {
this.$el.html(this.template);
return this;
}
});
Initially I thought that Collection is empty, but console.log(Colors) shows that there are items in collection. Moreover if I use Meteor.render(... -> Template.colors({colors: Colors.find()}) ) it renders template end show Collection items there.
Meteor version 0.6.6.3 (Windows 7, 64bit)
Mongo - connected to MongoLab
Thank you for any help.
Jev.
Can't really explain this well in the comments, so here is a very, very simple example of using the Meteor template engine. This is a 100% functional app, showcasing basic reactivity. Note that I never call render() or renderList() anywhere.
All this app does is show a button, that when clicked, adds a number to a list. The number is reactively added to the list, even though I never do anything to make that reactivity explicit. Meteor's templates are automatically reactive! Try it out - this is all of the code.
numbers.html:
<body>
{{> numberList}}
</body>
<template name="numberList">
<ul>
{{#each numbers}}
<li>{{number}}</li>
{{/each}}
</ul>
<button>Click Me</button>
</template>
numbers.js:
var Numbers = new Meteor.Collection("numbers");
if (Meteor.isClient) {
Template.numberList.numbers = function() {
return Numbers.find();
};
var idx = 0;
Template.numberList.events({
"click button": function() {
Numbers.insert({
number: idx
});
idx++;
}
});
}
The code below shows one row from a table, and the JavaScript-code to handle the template. The code works, but it sets the disabled-attribute on all the buttons in the table. I only want it for the one button-element that is pushed.
Question: What is the best way to conditionally set the correct element as disabled in Meteor.js?
In my HTML-file:
<template name="userRow">
<tr>
<td>{{ username }}</td>
<td>
<select class="newRole">
{{{optionsSelected globalRoles profile.role }}}
</select>
</td>
<td>
Disabled: {{disabledAttr}}
{{#isolate}}
<button type="button" {{disabledAttr}} class="btn btn-xs btn-primary saveUser">Save</button>
{{/isolate}}
</td>
<td><button type="button" class="btn btn-xs btn-danger deleteUser">Delete</button></td>
</tr>
And in my .js-file:
var newUserRole;
var savedDep = new Deps.Dependency;
var saved;
var disabledDep = new Deps.Dependency;
var disabledAttr = "";
Template.userRow.saved = function () {
savedDep.depend();
return saved;
};
Template.userRow.disabledAttr = function () {
disabledDep.depend();
return disabledAttr;
};
Template.userRow.events({
'change .newRole' : function (event) {
newUserRole = event.target.value;
},
'click .saveUser' : function (event) {
disabledAttr = "disabled";
disabledDep.changed();
Meteor.call('updateUser',
{
userId: this._id,
role: newUserRole
},
function (error, result) {
if (error) {
saved = "NOT saved, try again!";
} else {
saved = "Saved!";
savedDep.changed();
};
});
return false;
}
});
To answer your question:
All of your rows are using the same Dependency object, so when one row changes the object, all the other rows respond.
To fix this you can create a new Dependency object for each row.
For example:
Template.userRow.created = function () {
this.disabledDep = new Deps.Dependency;
};
And update all of your code to use the template's disabledDep instead of the 'global' one. That should solve your problem.
But let's talk about your goal here:
It looks like you want to render your rows differently while saving, until they're confirmed server side.
A cleaner way to do this is to take advantage of Meteor's isSimulation method. For example:
// Put this in a file that will be loaded on both the client and server
Meteor.methods({
add_item: function (name) {
Items.insert({name: name,
unconfirmed: this.isSimulation});
}
});
This example is using inserts, but you can use the same technique for updates.
Now each document in your collection will have an 'unconfirmed' field, which you can use to change your view:
Template.userRow.disabledAttr = function () {
return this.unconfirmed ? "disabled" : "";
};
I'm new to Meteor and barely understand any of it but let's say I have a collection called mycollection, declared way up top so it's available in both the client and server section:
mycollection = new Meteor.Collection('MyDumbCollection');
And then I have something like this:
if (Meteor.isClient) {
Deps.autorun(function() {
Meteor.subscribe('mycollectionSubscription');
});
Template.myshittytemplate.rendered = function() {
$("#heynow").prepend(shitfuck).dosomething();
godammit = thisfuckingthing;
//paraphrasing
mycollection.insert({thing1: thisfuckingthing});
};
}
if (Meteor.isServer) {
Meteor.publish('mycollectionSubscription', function () {
return mycollection.find();
});
};
And then in my template:
<template name="myshittytemplate">
<div id ="heynow">
{{#each mycollection}}
{{{thing1}}}
{{/each}}
</div>
</template>
What I'm trying to do is have the 'thisfuckingthing' html that's created in the #heynow div saved to the collection and published to everybody. If there's a way to make Meteor simply observe changes to the dom and save them, that's even better.
I do have autopublish uninstalled, if that makes a difference. Halp.
In client Template
Template.myshittytemplate.mycollection = function() {
return mycollection.find({}).fetch();
};
Template.myshittytemplate.rendered = function() {
$(function(){
$("#heynow").prepend(shitfuck).dosomething();
godammit = thisfuckingthing;
//paraphrasing
mycollection.insert({thing1: thisfuckingthing},function(err,_id){
if(err){
console.log(err);
return;
});
console.log(_id);
});
};
}
I needed this in the Client part:
Template.myshittytemplate.mycollection = function() {
return mycollection.find();
};
Hopes this helps somebody!