Angular-Fullstack get current user - javascript

I'm not able to get the current user ID in the controller. I have this:
controller.js:
constructor(Auth) {
this.getCurrentUser = Auth.getCurrentUserSync;
// console.log(this.getCurrentUser()._id) returns undefined
}
But, if I print in the html:
p {{ctrl.getCurrentUser()._id}}
I get perfectly the user ID.
Why is this happening?? How can I get the user ID in the controller?
EDIT:
The Auth.getCurrentUser() function looks like:
function getCurrentUser(callback) {
var value = _.get(currentUser, '$promise') ? currentUser.$promise : currentUser;
return $q.when(value).then(function (user) {
safeCb(callback)(user);
return user;
}, function () {
safeCb(callback)({});
return {};
});
}

Just access like,
console.log($$state.value.data._id);
DEMO
var userinfo = { $$state: {
status: 1,
value: {
data: {
__v: 0,
_id: "596b33283055cd0f2442cd85"
}
}
}
}
console.log(userinfo.$$state.value.data._id);

Related

Meteor - How to give value from child to parent function?

I want to send value of result from child to parent element. I used Session.set and Session.get and it works fine but I know that is not good practice because Sessions are global. So, I wanted to try something like reactive var or reactive dict but both of them are giving me only object as a result. What should I do or how should I take specific things from that object? (I am storing JSON inside that ReactiveVar or Dict and I know that they are really bad with JSON. Thank you for help!
Template.companyCreate.helpers({
CompanyName : function () {
if (Meteor.user() || Roles.userIsInRole(Meteor.user(),['admin','adminCreator'], 'companyAdmin')) {
Meteor.call('findCompany', function(err, result) {
if (err) {
console.log(err.reason)
}
else {
//this is where I want to take result and give it to parent function
}
});
return //this is where I want to take result that was given from child function and return it to CompanyName
}
else {
Router.go('/nemate-prava')
}
},
UPDATED CODE
Template.companyCreate.onCreated(function Poruke() {
this.message = new ReactiveVar(' ');
let self = this;
let user = Meteor.user();
let companyNameHandler = Template.currentData().companyNameHandler;
self.companyName = new ReactiveVar();
if (user && Roles.userIsInRole(user,['admin','adminCreator'], 'companyAdmin')) {
Meteor.call('findCompany', function(err, result) {
if (err) {
console.log(err.reason)
}
else {
self.companyName.set(result);
companyNameHandler(result);
}
});
}
else {
Router.go('/nemate-prava')
}
});
Template.companyCreate.helpers({
message: () => { return Template.instance().message.get() },
isNotInRole : function() {
if (!Meteor.user() || !Roles.userIsInRole(Meteor.user(),['admin','adminCreator'], 'companyAdmin')) {
return true;
}
else {
return false;
}
},
CompanyName : function () {
return Template.instance().companyName.get();
}
});
Template.companyCreate.events({
'submit form': function(event, template) {
var Ime = event.target.Ime.value;
event.preventDefault();
Meteor.call('companyCheck', Ime, function(error, result) {
if (error) {
console.log(error.reason);
template.message.set(error.reason);
alert(error.reason);
}
else {
event.target.Ime.value = "";
console.log('Kompanija je uspesno kreirana!');
template.message.set("Uspesno!");
}
})
},
});
Method:
'findCompany'(){
ImeKompanije = firma.findOne({AdminID: this.userId}).ImeKompanije
if (typeof ImeKompanije == 'undefind') {
throw new Meteor.Error(err, "Greska!");
}
return ImeKompanije;
},
});
Router:
Router.route('/comp/:ImeKompanije', {
name: 'companyProfile',
template: 'companyProfile',
waitOn: function() {
return Meteor.subscribe('bazaFirmi', this.params.ImeKompanije)
},
action: function() {
this.render('companyProfile', {
data: function() {
return firma.findOne({ImeKompanije: this.params.ImeKompanije});
}
});
},
});
ok, there's a lot to unwind here. let's start with something small.
if (Meteor.user() || Roles.userIsInRole(Meteor.user(),['admin','adminCreator'], 'companyAdmin')) {
i think this line is meant to say, "if the user is an admin". but it's really saying, "if the user is logged in." if you meant the first one, then change the "||" to an "&&".
bigger issue is you're making a server call in a helper. helpers can get called over and over, so think of them as something that simply returns data. it should not have any side effects, such as making a server call or (yikes) re-routing the user.
so let's move all that side effect code to the onCreated() and capture the company name so it can be returned from the helper. We'll also get set up to return the company name to the parent.
Template.companyCreate.onCreated(function() {
let self = this;
let user = Meteor.user();
let companyNameHandler = Template.currentData().companyNameHandler;
self.companyName = new ReactiveVar();
if (user && Roles.userIsInRole(user,['admin','adminCreator'], 'companyAdmin')) {
Meteor.call('findCompany', function(err, result) {
if (err) {
console.log(err.reason)
}
else {
self.companyName.set(result);
companyNameHandler(result);
}
});
}
else {
Router.go('/nemate-prava')
}
});
now the helper is really simple, it just returns the data that was saved to the template's reactive var:
Template.companyCreate.helpers({
CompanyName : function () {
return Template.instance().companyName.get();
}
});
the last part is setting up the handler to return the data to the parent. it's bad form to have the client reaching back up to its parent, so i usually have the parent give to the child a function it can call. usually i'll do that when the child says, "i've done my work," but here we can use it to provide that data. i'll have to make some assumptions on what your parent looks like.
<template name="Parent">
{{> companyCreate companyNameHandler=getCompanyNameHandler}}
</template>
Template.Parent.helpers({
getCompanyNameHandler() {
let template = Template.instance();
return function(companyName) {
console.log(companyName);
// you can also access the parent template through the closure "template"
}
}
});
the parent's helper returns a function that is passed to the client. when the client calls it, it will execute in the parent's closure. you can see i set up a variable called "template" that would allow you to, say, access reactive vars belonging to the parent.
UPDATE: in case the handler isn't known as is inside the Meteor.call() scope, we can try using it through a reactive var.
Template.companyCreate.onCreated(function() {
let self = this;
let user = Meteor.user();
self.companyNameHandler = new ReactiveVar(Template.currentData().companyNameHandler);
self.companyName = new ReactiveVar();
if (user && Roles.userIsInRole(user,['admin','adminCreator'], 'companyAdmin')) {
Meteor.call('findCompany', function(err, result) {
if (err) {
console.log(err.reason)
}
else {
self.companyName.set(result);
let fn = self.companyNameHandler.get();
fn(result);
}
});
}
else {
Router.go('/nemate-prava')
}
});

Jasmine test complaining about 'undefined' is not an object

I have checked other questions similar to my problem. but this problem can apparently be different in every case.
Angular Jasmine Test complains
TypeError: 'undefined' is not an object (evaluating 'fields.forEach')at discoverDependentFields
Here is my discoverDependentFields function
discoverDependentFields($scope.response.Fields);
function discoverDependentFields(fields) {
fields.forEach(function (field) {
field.DependencyFieldEvaluated = '';
if (field.DependencyField) {
var foundFields = fields.filter(function (fieldToFind) { return fieldToFind.Name === field.DependencyField; });
if (foundFields.length === 1) {
field.DependencyFieldEvaluated = foundFields[0];
}
}
});
}
and in the test I have this bit
this.controller('MyController', {
'$scope': this.scope,
}
});
this.scope.response.Fields = [
{
Name: "UserIdentity",
Value: {
"FirstName": "John"
},
PropertyName: "User.Identity"
}
];
I use the value of field.DependencyFieldEvaluated in a function in a directive like this
function dependencyMet(field) {
var dependentField = field.DependencyFieldEvaluated;
var met = compareToDependencyValue(field, dependentField.Value);
return met;
}
I have no idea why it is complaining
If
discoverDependentFields($scope.response.Fields);
is a line in your controller, then you need to setup the $scope.response.Fields data before instantiating the controller. In other words, swap the order of operations in your test to be
this.scope = {};
// or maybe this.scope = $rootScope.$new()
this.scope.response = {
Fields: [{
Name: "UserIdentity",
Value: {
FirstName: "John"
},
PropertyName: "User.Identity"
}]
};
this.controller('MyController', {
$scope: this.scope,
});

Meteor: Reactive joins exposes intermediate data

I'm using publish-composite to perform a reactive join (I'm sure the specific package does not matter). And I am seeing that the intermediate data gets pushed to the client.
In the following example:
Meteor.publishComposite('messages', function(userId) {
return {
find: function() {
return Meteor.users.find(
{ 'profile.connections.$': userId }
);
},
children: [{
find: function(user) {
return Messages.find({author: user._id});
}
}]
}
});
All the users that has userId in profile.connections get exposed to the client. I know that can create a mongodb projection so the sensitive stuff is not exposed. But I was wondering if I can just prevent the first find() query cursor from getting to the client at all.
Are you trying to only publish messages for a particular user if that user is a connection with the logged on user? If so, maybe something like this would work:
Meteor.publishComposite('messages', function(userId) {
return {
find: function() {
return Meteor.users.find(this.userId);
},
children: [{
find: function(user) {
return Meteor.users.find(
{ 'profile.connections.$': userid }
);
},
children: [{
find: function(connection, user) {
return Messages.find({author: connection._id});
}
}]
}]
};
});
That would be equivalent to something like :
Meteor.publish('message',function(userId) {
var user = Meteor.users.find({_id : this.userId, 'profile.connections.$' : userId});
if (!!user) {
return Messages.find({author: userId});
}
this.ready();
});

Transform data before rendering it to template in meteor

I want to return a single document with the fields joined together. That is, a result like as follows
{
_id: "someid",
name: "Odin",
profile: {
game: {
_id: "gameid",
name: "World of Warcraft"
}
}
}
I have a route controller which is fairly simple.
UserController = RouteController.extend({
waitOn: function () {
return Meteor.subscribe('users');
},
showAllUsers: function () {
this.render('userList', {
data: Meteor.users.find()
})
}
});
I've tried changing my data like so:
this.render('userList', {
data: Meteor.users.find().map(function (doc) {
doc.profile.game = Games.findOne();
return doc;
})
});
However, this does not have the intended effect of adding "game" to the user. (and yes, Games.findOne() has a result)
How can you transform the results of a cursor in meteor and iron:router?
Try defining your data as a function so it can be dynamically re-executed when needed.
UserController = RouteController.extend({
waitOn: function () {
return Meteor.subscribe('users');
},
showAllUsers: function () {
this.render('userList', {
data: function(){
return Meteor.users.find().map(function (doc) {
doc.profile.game = Games.findOne();
return doc;
});
}
});
}
});
Given your use of easy search, what might be simpler is just to define a template helper for profile
Template.userList.helpers({
profile: function(){
var game = Games.findOne({_id: this.gameId});
return { game: { _id: game._id, name: game.name }};
}
});
This assumes a single game per user. If you have more than one then you can iterate over a cursor of Games instead.

MongoDB $pull not working

I am building a Meteor app and I have Contests/Entries collections. When someone enters the contest, their user_id is pushed into the Contest.entered_users array with $addToSet. Here is the code:
entryInsert: function(entryAttributes) {
check(Meteor.userId(), String);
check(entryAttributes, {
contest_id: String
});
var user = Meteor.user();
var entry = _.extend(entryAttributes, {
user_id: user._id,
user_name: user.profile.name,
submitted: new Date(),
submitted_day: moment().format('MMM D')
});
var currentContest = Contests.findOne(entryAttributes.contest_id);
// Check to make sure that the person has not already entered the giveaway
if (currentContest.entered_users.indexOf(entry.user_id) !== -1) {
throw new Meteor.Error('invalid', "You have already entered the giveaway");
} else {
Contests.update(
currentContest._id,
{
$addToSet: {entered_users: entry.user_id},
$inc: {entries: 1}}
);
}
// Create entry in order to get the entry id
var entryId = Entries.insert(entry, function(err) {
if (err) {
alert(err.reason);
}
});
return {
_id: entryId
}
}
I want to remove a persons user_id from the Contest.entered_users array when an entry is removed. I am trying to use $pull but it doesn't appear to be working... When I remove an entry, the entry.user_id is still in the contest.entered_users array. Here is the relevant code:
'click .entry-delete': function(e, tmpl) {
e.preventDefault();
var currentEntry = this;
var currentEntryId = this._id;
var contestId = Contests.findOne(currentEntry.contest_id);
// Update the contest by removing the entry's useer_id from entered_users
Meteor.call('contestRemoveEntry', contestId, currentEntry, function(error) {
if (error) {
alert(error.reason);
}
});
Meteor.call('entryRemove', currentEntryId, function(error) {
if(error) {
alert(error.reason);
}
});
}
Here is the contestRemoveEntry method:
contestRemoveEntry: function(contestId, currentEntry) {
Contests.update({ _id: contestId }, { $pull: { entered_users: currentEntry.user_id } } );
}
Any ideas as to why this is not working? I've tried other SO solutions but nothing seems to be working.
It appears that this is the correct way to make $pull work:
Contests.update(contestId, { $pull: { entered_users: currentEntry.user_id } } );

Categories