How to increment helper variable count in meteor? - meteor

I need to know about to increment helper variable count in meteor.
For example :
<head>
<title>hello</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{> hello}}
</body>
<template name="hello">
<button>Click Me</button>
{{#each arr}}
{{counter}} <!-- How to get the foo index here? --> {{name}}
{{/each}}
</template>
Js Code :
if (Meteor.isClient) {
// counter starts at 0
Template.hello.helpers({
counter: function () {
return Session.get('counter');
}
});
Template.hello.helpers({
arr: function () {
console.log(Session.get('arrres'));
return Session.get('arrres');
}
});
Template.hello.events({
'click button': function () {
Session.set('counter', 0);
Meteor.call('arrfun',10, function (error, res) {
if (!error)
{ arrres = res;
Session.set('arrres', arrres);
console.log(res);
}
else{}
} );
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
Meteor.methods({
arrfun:function arrfun(properties, callback)
{
var obj = [];
for(var i = 0 ; i < 10; i++)
{
var obj1 = new Object();
obj1.name = 'abc'+i;
obj.push(obj1);
}
return obj;
}
});
});
}
The above 'arr' contains list of names that present in object.Now can iterate 'arr' it will comes names.
now can we print names as like 1 abc
2 xyz until 'arr' completed.
So how can we print numbers from 1 to 'arr' length before names.
So please suggest me what to do for this.

It's a little hard to interpret your question but I think you want this:
Template.hello.events({
'click button': function(event) {
Session.set('counter', Math.round(Math.random() * 10));
}
});
Template.hello.helpers({
'arr': function() {
var counter = Session.get('counter');
var arr = [];
for(var i = 0; i < counter; i++) {
arr.push(i + 1);
}
return arr;
}
});
And in your hello template:
<ul>
{{#each arr}}
<li>{{this}}</li>
{{/each}}
</ul>
This will generate a random number between 0-10 every time you click the button, and then the template will count up to this random number in sequence.

Related

ionic slide box issue do not show dynamic data from DB (i'm using $ionicSlideBoxDelegate.update())

i am trying to show a dynamic data on the ionic slide box with ng-repeat. i am using services to get the data from my sqlite DB but i get nothing. i don't know what to do after 3 days with this issue, here is my code:
template.html
<ion-view>
<ion-nav-title>{{simple.title}}</ion-nav-title>
<ion-content>
<div class="row">
<div class="col col-33 col-offset-33">
<h1 style="font-size: 72px !important;">{{simple.content}}</h1>
</div>
</div>
<div class="row">
<div class="col">
<ion-slide-box show-pager="false" does-continue="true">
<ion-slide ng-repeat="senci in sencillo">
<div class="box">
<h1 style="font-size: 52px !important;">{{senci.sound_title}}</h1>
</div>
</ion-slide>
</ion-slide-box>
</div>
</div>
</ion-content>
</ion-view>
my service.js
angular.module('starter.services', [])
.factory('DBA', function($cordovaSQLite, $q, $ionicPlatform) {
var self = this;
// Handle query's and potential errors
self.query = function (query, parameters) {
parameters = parameters || [];
var q = $q.defer();
$ionicPlatform.ready(function () {
$cordovaSQLite.execute(db, query, parameters)
.then(function (result) {
q.resolve(result);
}, function (error) {
console.warn('I found an error');
console.warn(error);
console.log(error.code + ' / ' + error.message);
q.reject(error);
});
});
return q.promise;
};
// Proces a result set
self.getAll = function(result) {
var output = [];
for (var i = 0; i < result.rows.length; i++) {
output.push(result.rows.item(i));
}
return output;
};
// Proces a single result
self.getById = function(result) {
var output = null;
output = angular.copy(result.rows.item(0));
return output;
};
return self;
})
.factory('Sounds', function(DBA) {
var self = this;
self.getSimple = function(simpleId) {
var parameters = [simpleId];
return DBA.query("SELECT * FROM letters WHERE Id = (?)", parameters)
.then(function(result) {
return DBA.getById(result);
});
};
self.getSimpleArr = function(Id) {
var parameters = [Id];
return DBA.query("SELECT * FROM words WHERE letter_id = (?)", parameters)
.then(function(result) {
return DBA.getById(result);
});
};
return self;
});
controller.js
.controller('SoundsSimpleCtrl', function($scope, Sounds, $stateParams, $ionicSlideBoxDelegate) {
$scope.sencillo = [];
$scope.getSimple = function($stateParams) {
Sounds.getSimple($stateParams.simpleId).then(function(single){
$scope.simple = single;
$scope.getArrSimple($scope);
});
};
$scope.getArrSimple = function($scope){
Sounds.getSimpleArr($scope.simple.Id).then(function(detalle){
$scope.sencillo = detalle;
$ionicSlideBoxDelegate.update();
});
};
$scope.getSimple($stateParams);
});
i hope you guys can help me, regards.
Hi people i resolved my problem, i had a bad SQl Request, im so sorry for be annoying, i just changed to use my service function from getById() to getAll() (these functions are being taken from DBA Factory) like this:
self.getSimpleArr = function(value) {
var parameters = [value];
return DBA.query("SELECT * FROM words WHERE letter_id = (?)",parameters)
.then(function(result){
return DBA.getAll(result);
});
};
the getById() function was returning only the first row of the request, absolutely MY BAD. Regards

How to perform Meteor.call on Session variable change

Here is what I have:
Templates:
<body>
{{> resultSession}}
{{> resultMethod}}
</body>
<template name="resultSession">
<button>Click me</button>
<p>Session.get('length') returned {{returned}}</p>
</template>
<template name="resultMethod">
<p>Meteor.call returned {{returned}}</p>
</template>
Client-side:
Template.resultSession.events({
'click button': function () {
Session.set('length', Math.floor((Math.random() * 20) + 1));
}
});
Template.resultSession.helpers({
returned: function () {
return Session.get('length');
}
});
Template.resultMethod.helpers({
returned: function() {
Meteor.call('returnArray', Session.get('length'), function (err, res) {
return res.length;
});
}
});
Server-side:
Meteor.methods({
'returnArray': function (length) {
var arr = [];
arr[length - 1] = 0;
return arr;
}
});
TL;DR
You can look at code and play with it here http://meteorpad.com/pad/AkBZq4ZFjJuQuzztz/Meteor.call-on-Session-change
As you can see, my method accepts number and returns the array with length equal to number.
The question is how can I make Meteor.call fire each time Session variable changes?
P.S. Values are returned to two different templates on purpose
Your reactive code is working perfectly.
If you put a console.log in the Meteor.call you will see that the correct answer is coming back from the server.
Template.resultMethod.helpers({
returned: function() {
Meteor.call('returnArray', Session.get('length'), function (err, res) {
console.log('it came back ' + res.length);
return res.length;
});
}
});
I have put a Session variable into the return from the server, so now you can see that your reactive code works very simply - no need for complicated autorun stuff.
<template name="resultMethod">
<p>Meteor.call returned {{returned}}</p>
</template>
Then in the resultMethod helper:
Template.resultMethod.helpers({
returned: function() {
Meteor.call('returnArray', Session.get('length'), function (err, res) {
Session.set('fromServer', res.length + '');
});
return Session.get('fromServer');
}
});
Like #saimeunt said, use Tracker.autorun
Templates:
<body>
{{> resultSession}}
{{> resultMethod}}
</body>
<template name="resultSession">
<button>Click me</button>
<p>Session.get('length') returned {{returned}}</p>
</template>
<template name="resultMethod">
<p>Meteor.call returned {{returned}}</p>
</template>
And code:
Template.resultMethod.rendered = function() {
this.autorun(function (){
Meteor.call('returnArray', Session.get('length'), function (err, res) {
Session.set('result', res);
});
});
}
Template.resultSession.helpers({
returned: function () {
return Session.get('length');
}
});
Template.resultMethod.helpers({
returned: function() {
return Session.get('result');
}
});
Autorun inside rendered stops when the template is not rendered
You could simply refactor your code to call the Meteor method on click event ?
Template.resultSession.events({
'click button': function () {
var length = Math.floor((Math.random() * 20) + 1);
Session.set('length', length);
Meteor.call('returnArray', length, function (err, res) {
Session.set('result', res.length);
});
}
});
Template.resultSession.helpers({
returned: function () {
return Session.get('length');
}
});
Template.resultMethod.helpers({
returned: function() {
return Session.get('result');
}
});
You could also use Tracker.autorun to track modifications of your Session variable and rerun arbitrary code.
Tracker.autorun(function(){
var length = Session.get("length");
console.log("length new value =", length);
});

Meteor - cursor with limit set isn't reactive

I don't know if this is bug, but when i specify limit, the cursor on the client isn't reactive if some data that match the query already exists in the client collection.
For instance if have limit: 4 and there is already 1 record that match, than
it returns that one record and when next 3 records, which machtes the query, arrives from the server, the cursor isn't reactive (i am expecting
it will be evaluated again and it will return all those 4 records).
I found it because when i uncomment the line where i am fetching all records, my app works (because that cursor will reflect that new data are available). You can see that query is same, only except that limit.
messages = Messages.find(selector, {sort: {created: -1}, limit: MessagesAPI.LIMIT}).fetch();
//Messages.find(selector, {sort: {created: -1}}).fetch());
// if i uncomment the previous line, it works
More code
getMeteorState: function () {
console.log("zde");
var time = this.getParams().time;
var dir = this.getParams().dir;
//TODO: maybe check time and dir validity or let it crash ?
var ready = Session.get("messages-ready");
var params = {sort: MessagesAPI.sort.NEW, dir: dir == "prev" ? MessagesAPI.dir.PREV : MessagesAPI.dir.NEXT};
if (time) {
var d = new Date();
d.setTime(time);
params.date = d;
}
Meteor.subscribe("messages", params, function () {
console.log("ready");
Session.set("messages-ready", true);
});
var messages = [];
if (ready) {
var selector = {};
if (time && dir) {
selector.created = {};
var cond = (dir == "prev" ? "$lt" : "$gt");
var date = new Date();
date.setTime(time);
selector.created[cond] = date;
}
messages = Messages.find(selector, {sort: {created: -1}, limit: MessagesAPI.LIMIT}).fetch();
//console.log(selector);
// when i uncomment this, it will work
//console.log(Messages.find(selector, {sort: {created: -1}}).fetch());
}
return {
messages: messages
};
},
It is reactive.
If I create a default app and mod it like so
Messages = new Mongo.Collection("messages");
if (Meteor.isClient) {
// counter starts at 0
Session.setDefault("counter", 0);
Template.hello.helpers({
counter: function () {
return Session.get("counter");
},
messages: function() {
var messages = Messages.find({},{sort: {text: -1}, limit: 4}).fetch();
return messages;
}
});
Template.hello.events({
'click button': function () {
Session.set("counter", Session.get("counter") + 1);
Messages.insert({text: Session.get("counter")});
}
});
}
and html
<head>
<title>reactive</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{> hello}}
</body>
<template name="hello">
<button>Click Me</button>
<p>You've pressed the button {{counter}} times.</p>
<div>
{{#each messages}}
{{text}}
{{/each}}
</div>
</template>
No problem. Manual insert via Mongo console reactively updates

MeteorJS: Collection.find fires multiple times instead of once

I have an app that when you select an industry from a drop down list a collection is updated where the attribute equals the selected industry.
JavaScript:
Template.selector.events({
'click div.select-block ul.dropdown-menu li': function(e) {
var selectedIndex = $(e.currentTarget).attr("rel");
var val = $('select#industryPicker option:eq(' + selectedIndex + ')').attr('value');
var oldVal = Session.get('currentIndustryOnet');
if(val != oldVal) {
Session.set('jobsLoaded', false);
Session.set('currentIndustryOnet', val);
Meteor.call('countByOnet', val, function(error, results){
if(results > 0) {
Session.set('jobsLoaded', true);
} else {
getJobsByIndustry(val);
}
});
}
}
});
var getJobsByIndustry = function(onet) {
if(typeof(onet) === "undefined")
alert("Must include an Onet code");
var params = "onet=" + onet + "&cn=100&rs=1&re=500";
return getJobs(params, onet);
}
var getJobs = function(params, onet) {
Meteor.call('retrieveJobs', params, function(error, results){
$('job', results.content).each(function(){
var jvid = $(this).find('jvid').text();
var job = Jobs.findOne({jvid: jvid});
if(!job) {
options = {}
options.title = $(this).find('title').text();
options.company = $(this).find('company').text();
options.address = $(this).find('location').text();
options.jvid = jvid;
options.onet = onet;
options.url = $(this).find('url').text();
options.dateacquired = $(this).find('dateacquired').text();
var id = createJob(options);
console.log("Job Created: " + id);
}
});
Session.set('jobsLoaded', true);
});
}
Template.list.events({
'click div.select-block ul.dropdown-menu li': function(e){
var selectedIndex = $(e.currentTarget).attr("rel");
var val = $('select#perPage option:eq(' + selectedIndex + ')').attr('value');
var oldVal = Session.get('perPage');
if(val != oldVal) {
Session.set('perPage', val);
Pagination.perPage(val);
}
}
});
Template.list.jobs = function() {
var jobs;
if(Session.get('currentIndustryOnet')) {
jobs = Jobs.find({onet: Session.get('currentIndustryOnet')}).fetch();
var addresses = _.chain(jobs)
.countBy('address')
.pairs()
.sortBy(function(j) {return -j[1];})
.map(function(j) {return j[0];})
.first(100)
.value();
gmaps.clearMap();
$.each(_.uniq(addresses), function(k, v){
var addr = v.split(', ');
Meteor.call('getCity', addr[0].toUpperCase(), addr[1], function(error, city){
if(city) {
var opts = {};
opts.lng = city.loc[1];
opts.lat = city.loc[0];
opts.population = city.pop;
gmaps.addMarker(opts);
}
});
})
return Pagination.collection(jobs);
} else {
jobs = Jobs.find()
Session.set('jobCount', jobs.count());
return Pagination.collection(jobs.fetch());
}
}
In Template.list.jobs if you console.log(addresses), it is called 4 different times. The browser console looks like this:
(2) 100
(2) 100
Any reason why this would fire multiple times?
As #musically_ut said it might be because of your session data.
Basically you must make the difference between reactive datasources and non reactive datasources.
Non reactive are standard javascript, nothing fancy.
The reactive ones however are monitored by Meteor and when one is updated (insert, update, delete, you name it), Meteor is going to execute again all parts which uses this datasource. Default reactive datasources are: collections and sessions. You can also create yours.
So when you update your session attribute, it is going to execute again all helper's methods which are using this datasource.
About the rendering, pages were rendered again in Meteor < 0.8, now with Blaze it is not the case anymore.
Here is a quick example for a better understanding:
The template first
<head>
<title>test</title>
</head>
<body>
{{> hello}}
</body>
<template name="hello">
<h1>{{getSession}}</h1>
<h1>{{getNonReactiveSession}}</h1>
<h1>{{getCollection}}</h1>
<input type="button" name="session" value="Session" />
<input type="button" name="collection" value="Collection" />
</template>
And the client code
if (Meteor.isClient) {
CollectionWhatever = new Meteor.Collection;
Template.hello.events({
'click input[name="session"]': function () {
Session.set('date', new Date());
},
'click input[name="collection"]': function () {
CollectionWhatever.insert({});
}
});
Template.hello.getSession = function () {
console.log('getSession');
return Session.get('date');
};
Template.hello.getNonReactiveSession = function () {
console.log('getNonReactiveSession');
var sessionVal = null;
new Deps.nonreactive(function () {
sessionVal = Session.get('date');
});
return sessionVal;
};
Template.hello.getCollection = function () {
console.log('getCollection');
return CollectionWhatever.find().count();
};
Template.hello.rendered = function () {
console.log('rendered');
}
}
If you click on a button it is going to update a datasource and the helper method which is using this datasource will be executed again.
Except for the non reactive session, with Deps.nonreactive you can make Meteor ignore the updates.
Do not hesitate to add logs to your app!
You can read:
Reactivity
Dependencies

Have Meteor update a string every second

This is Meteor's default HTML:
<head>
<title>random-test</title>
</head>
<body>
{{> hello}}
</body>
<template name="hello">
<h1>Hello World!</h1>
{{greeting}}
<input type="button" value="Click" />
</template>
And this is Meteor's default Javascript code:
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to random-test.";
};
Template.hello.events({
'click input' : function () {
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
I changed the Javascript so I could have it update {{greeting}} every second:
if (Meteor.isClient) {
Template.hello.greeting = "hi";
Meteor.setInterval(function() {
Session.set("greeting", "hello");
console.log("Hi");
}, 1000);
Template.hello.events({
'click input' : function () {
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
It is console.logging "hi" every second. However, it is either not updating the value of greeting or Session.get isn't updating its value as it should (according to Meteor docs).
You need to return the Session.get('greeting') in a helper:
Template.hello.greeting = function() {
return Session.get('greeting');
}
Having Template.hello.greeting = "hi"; makes the template not dependent on Session.get('greeting'), so changes to that "session variable" won't cause any re-renderings. Or what do you expect to happen?

Resources