Reactive array is empty - meteor

I'm using Meteor CollectionFS to upload files. I'm using ephmer:reactive-array to store the file IDs after they're stored in the collection. The following is the code:
Template.myFileHandler.created = function () {
this.fileIds = new ReactiveArray();
}
I upload the files as specified in the CollectionFS documentation:
Template.myFileHandler.events = function () {
'submit #myFileForm': function (event, template) {
for(var i = 0; i < fileList.length; i++) {
var fsFile = FS.File(fileList[i]);
UserDocuments.insert(file, function (err, fileObj) {
Template.instance().fileIds.push(fileObj._id);
});
}
console.log(Template.instance().fileIds.get().length)
}
}
When I do the console.log, I'm getting the length: 0. How do I store the IDs in the reactive array?

You are just passing a callback in your insert function. But the callback is asynchrous, and will only execute after the insert is done.
So your code is still working. Try putting your console.log in your callback like that :
Template.myFileHandler.events = function () {
'submit #myFileForm': function (event, template) {
for(var i = 0; i < fileList.length; i++) {
var fsFile = FS.File(fileList[i]);
UserDocuments.insert(file, function (err, fileObj) {
Template.instance().fileIds.push(fileObj._id);
console.log(Template.instance().fileIds.get().length); // Here it will show 1
});
}
console.log(Template.instance().fileIds.get().length); // Here, the insert hasn't happened yet
}
}

Related

How come this isn't working Sync/Async issues with Meteor.methods

This is weird but when I call a external function from Meteor.method function it will always return undefined in the client I tried Meteor.wrapAsync but I think I'm doing something wrong. Here is my code:
var demoFunction = function () {
//database operations
var user = this.userId;
if (!user)
return;
var count = Users.aggregate([
{ $group: {_id: null, count: {$sum: 1}} }
]);
if (count[0] && count[0].count)
return count[0].count;
return 0;
}
Meteor.methods({
// NOT WORKING, How can I make this work?
methodDemo: function () {
var result = demoFunction ();
return result;
},
// Works
methodDemo2: function () {
//database operations
var user = this.userId;
if (!user)
return;
var count = Users.aggregate([
{ $group: {_id: null, count: {$sum: 1}} }
]);
if (count[0] && count[0].count)
return count[0].count;
return 0;
}
});
// Call from client
Meteor.call("methodDemo", function (err, res) { });
calling external functions doesn't work the same way if I put the code inside the meteor method why?
Try using Meteor.userId() in your function instead of this.userId. I think you are loosing the value of this when calling your function causing it to exit early.
Since you declared the function with a var it is scoped outside of methodDemo().
You could declare the function globally by removing var or move the demoFunction() code into methodDemo().

Get value returned from another method

In a Template helper, is it possible to get from a method a value returned by another method?
In example
Template.postsList.helpers({
posts: function () {
return Posts.find({});
},
nextPath: function () {
// how to return here the number of posts from the query
// in the posts method?
}
});
You can just refactor the code so you have a shared way to obtain the posts cursor:
var postsCursor = function() {
return Posts.find();
};
Template.postsList.helpers
posts: postsCursor,
nextPath: function () {
var count = postsCursor().count();
// do something with count
}
});

How to access meteor call in Template event

I am making a meteor call and getting array in return on the client side.
I want to use this array in an event inside Template but the array is not recognized outside the meteor call.
How to access this array in a Template event?
if (Meteor.isClient) {
result=[];
Meteor.call('getApiResult', function (err, result) {
if (result) {
console.log("reached meteor call")
console.log(result);
}
});
Template.dpVar.events = {
'click .addproduct' : function (err) {
for (i = 0; i < result.length; i++) {
var Temp_Name = result[i];
var Temp_Val = document.getElementById(Temp_Name).value
console.log("temp name is ", Temp_Name);
productDB.insert({ Temp_Name: Temp_Val});
console.log("temp val is ", Temp_Val);
}
}
}//Client Ends
You aren't setting result, you are overloading the name ;-)
Try this, if it doesn't work, move result = [] into the global scope.
if (Meteor.isClient) {
result = [];
Meteor.call('getApiResult', function (err, res) {
if (res) {
console.log("reached meteor call")
console.log(res);
result = res;
}
});
Template.dpVar.events = {
'click .addproduct' : function (err) {
for (i = 0; i < result.length; i++) {
var Temp_Name = result[i];
var Temp_Val = document.getElementById(Temp_Name).value
console.log("temp name is ", Temp_Name);
productDB.insert({ Temp_Name: Temp_Val});
console.log("temp val is ", Temp_Val);
}
}
}
}

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

Setting $scope.items in Angular Binding

I have a service with the following function,
public object Get(AllUsers request)
{
var users = XYZ.GetAllUsers();
var userList = users.Cast<XYZ>();
return new AllUsers
{
UsersAcc = userList.Select(ConvertToEntity).ToList()
};
}
I am trying to get the results from angular controller.
function UserAccountController($scope, $location, $filter, UserAccount) {
#scope.items = function(){
var abc = UserAccount.query();
return abc.UsersAcc
}
}
Here is my Service
angular.module('userAccService', ['ngResource']).factory('UserAcc', function($resource) {
return $resource('/api/useracc/:id', {}, {
query: {
method: 'GET',
}
});
I am new to angular service, and can't seem to make it to work.
You need to create an array object and return it. After the query is done you can populate that same instance with the list UsersAcc. Keep in mind that $scope.items will be [] untill the query returns with data.
$scope.items = getUsersAcc();
function getUsersAcc() {
var dataArray = new Array();
UserAccount.query(function (data) {
var list = data.UsersAcc;
for (var i = 0, c = list.length; i < c; i++) {
dataArray.push(list[i]);
}
};
return dataArray;
};

Resources