AngularJS redirection after ng-click - javascript

I have a REST API that read/save data from a MongoDB database.
The application I use retrieves a form and create an object (a job) from it, then save it to the DB. After the form, I have a button which click event triggers the saving function of my controller, then redirects to another url.
Once I click on the button, I am said that the job has well been added to the DB but the application is jammed and the redirection is never called. However, if I reload my application, I can see that the new "job" has well been added to the DB. What's wrong with this ??? Thanks !
Here is my code:
Sample html(jade) code:
button.btn.btn-large.btn-primary(type='submit', ng:click="save()") Create
Controller of the angular module:
function myJobOfferListCtrl($scope, $location, myJobs) {
$scope.save = function() {
var newJob = new myJobs($scope.job);
newJob.$save(function(err) {
if(err)
console.log('Impossible to create new job');
else {
console.log('Ready to redirect');
$location.path('/offers');
}
});
};
}
Configuration of the angular module:
var myApp = angular.module('appProfile', ['ngResource']);
myApp.factory('myJobs',['$resource', function($resource) {
return $resource('/api/allMyPostedJobs',
{},
{
save: {
method: 'POST'
}
});
}]);
The routing in my nodejs application :
app.post('/job', pass.ensureAuthenticated, jobOffers_routes.create);
And finally the controller of my REST API:
exports.create = function(req, res) {
var user = req.user;
var job = new Job({ user: user,
title: req.body.title,
description: req.body.description,
salary: req.body.salary,
dueDate: new Date(req.body.dueDate),
category: req.body.category});
job.save(function(err) {
if(err) {
console.log(err);
res.redirect('/home');
}
else {
console.log('New job for user: ' + user.username + " has been posted."); //<--- Message displayed in the log
//res.redirect('/offers'); //<---- triggered but never render
res.send(JSON.stringify(job));
}
});
};

I finally found the solution ! The issue was somewhere 18inches behind the screen....
I modified the angular application controller like this :
$scope.save = function() {
var newJob = new myJobs($scope.job);
newJob.$save(function(job) {
if(!job) {
$log.log('Impossible to create new job');
}
else {
$window.location.href = '/offers';
}
});
};
The trick is that my REST api returned the created job as a json object, and I was dealing with it like it were an error ! So, each time I created a job object, I was returned a json object, and as it was non null, the log message was triggered and I was never redirected.
Furthermore, I now use the $window.location.href property to fully reload the page.

Related

How should I store current user details in EmberJS?

I have an EmberJS application generated using ember-cli. I'm currently using simple-auth with a custom authenticator.
In the authenticator, when the user logs in I want to save his details so that I can use it later.
I have the following code:
authenticate: function(options) {
var self = this;
return new Ember.RSVP.Promise(function(resolve, reject){
API.user.login(options.username, options.password, true).done(function(data) {
// #TODO: Save current user
resolve(data.id);
}).fail(function() {
reject();
});
});
},
User data is available in the variable data.user.
I tried using Ember.set('App.currentUser', data.user); but it's not working. What should I do?
I think it works easiest to use an initializer. Theres several ways you can resolve the user, I think it is easiest if you pass the user_email alongside the grant token from the API
//initializers/session-user.js
import Ember from "ember";
import Session from "simple-auth/session";
export function initialize(container) {
Session.reopen({
setCurrentUser: function() {
var accessToken = this.get('access_token');
var self = this;
if (!Ember.isEmpty(accessToken)) {
return container.lookup('store:main').find('user', {
email: self.get('user_email')
}).then(function (users){
self.set('currentUser', users.get('firstObject'));
});
}
}.observes('access_token')
});
}
export default {
name: 'session-user',
before: 'simple-auth',
initialize: initialize
};
Check this thread for where the idea of this came from: http://discuss.emberjs.com/t/best-practice-for-loading-and-persisting-current-user-in-an-authenticated-system/6987
And if you are using simple-auth > 0.8.0-beta.1 you will need to adjust the initializer
I ended up creating a custom Sessions controller and setting the current user object there, and then creating an alias from the application controller.
Something like what's in this article.

Getting Facebook Avatar in Meteor when Autopublish is removed

Currently when auto publish is removed, only {{currentUser.profile.name}} works.I'm trying to get {{currentUser.profile.first_name}} and the avatar from Facebook but have not been able to do so. Here is my code...
On the Server side:
Meteor.publish('userData', function() {
if(!this.userId) return null;
return Meteor.users.find(this.userId, {fields: {
'services.facebook': 1
}});
});
On Iron Router:
Router.configure({
waitOn: function() {
return Meteor.subscribe('userData');
}
});
From my understanding, I see that Meteor is publishing all the userData and then subscribing to it via Iron Router. What I don't understand is why this is not working -- as I think {{currentUser.profile.first_name}} should work but isn't.
Like Richard suggests, when a user is created, you can copy the services document to the profile doc.
Accounts.onCreateUser(function(options, user) {
// We still want the default hook's 'profile' behavior.
if (options.profile) {
user.profile = options.profile;
user.profile.memberSince = new Date();
// Copy data from Facebook to user object
user.profile.facebookId = user.services.facebook.id;
user.profile.firstName = user.services.facebook.first_name;
user.profile.email = user.services.facebook.email;
user.profile.link = user.services.facebook.link;
}
return user;
});
Your publication to get their first name and Facebook ID would look like this...
/* ============== Single User Data =============== */
Meteor.publish('singleUser', function(id) {
check(id, String);
return Meteor.users.find(id,
{fields: {'profile.facebookId': 1, 'profile.name': 1, 'profile.firstName': 1, 'profile.link': 1}});
});
You can access a user's Facebook avatar with a template helper function...
Template.profileView.helpers({
userPicHelper: function() {
if (this.profile) {
var id = this.profile.facebookId;
var img = 'http://graph.facebook.com/' + id + '/picture?type=square&height=160&width=160';
return img;
}
}
});
In your template, you can then use the following helper (provided you are wrapping this in a block that contains user data):
<img src="{{userPicHelper}}" alt="" />
I believe you're trying to access the first_name field from the services subdocument. It should be {{currentUser.services.facebook.first_name}}
If you want to transfer first_name to the profile subdocument, you can have the following event handler:
Accounts.onCreateUser(function(options, user) {
// ... some checks here to detect Facebook login
user.profile.firstName = user.services.facebook.first_name;
user.profile.lastName = user.services.facebook.last_name;
});

AngularJS tutorial Thinkster.io chapter 7

UPDATE: The tutorial was updated and the following question really no longer applies
Learning about AngularJS from the site thinkster.io (free ebook). But at the moment i'm stuck at chapter 7 - Creating your own user data using firebase. This is an tutorial about angularjs that works with firebase.
I have wrote all the code according to the site, but i'm getting these console errors when I want to register a user. It will create the user (in firebase -simplelogin), but not the user object (in firebase - data).:
TypeError: undefined is not a function
at Object.User.create (http://localhost:9000/scripts/services/user.js:46:19)
at http://localhost:9000/scripts/controllers/auth.js:32:22
etc.
This is the code (same as the site), the error is in the create() function and talks about the users.$save() function, snippet of User.create():
users.$save(username).then(function () {
setCurrentUser(username);
});
Complete code of user.js:
news.factory("User", function ($firebase, FIREBASE_URL, $rootScope, $log) {
var reference, users, User;
reference = new Firebase(FIREBASE_URL + "users");
users = $firebase(reference);
function setCurrentUser(username) {
$rootScope.currentUser = User.findByUsername(username);
}
$rootScope.$on("$firebaseSimpleLogin:login", function (event, authUser) {
var query = $firebase(reference.startAt(authUser.uid).endAt(authUser.uid));
query.$on("loaded", function () {
setCurrentUser(query.$getIndex()[0]);
});
});
$rootScope.$on("$firebaseSimpleLogin:logout", function () {
delete $rootScope.currentUser;
});
User = {
create: function (authUser, username) {
users[username] = {
md5_hash: authUser.md5_hash,
username: username,
"$priority": authUser.uid
};
$log.debug(users);
users.$save(username).then(function () {
setCurrentUser(username);
});
},
findByUsername: function (username) {
if (username) {
return users.$child(username);
}
},
getCurrent: function () {
return $rootScope.currentUser;
},
signedIn: function () {
return $rootScope.currentUser !== undefined;
}
};
return User;
});
Edit 1:
Registering a user now works, got it working (saving in firebase, simple login and data):
users = $firebase(reference).$asObject();
Notice the users.save() function:
create: function (authUser, username) {
users[username] = {
md5_hash: authUser.md5_hash,
username: username,
$priority: authUser.uid
};
$log.debug(users);
users.$save().then(function () {
setCurrentUser(users);
});
},
findByUsername: function (users) {
if (users) {
return users;
}
},
Edit 2:
Now I get an error at the log in of the user (see below), when I want to log in, I get an error on this this function, query.$on():
TypeError: undefined is not a function
at http://localhost:9000/scripts/services/user.js:26:19
$rootScope.$on("$firebaseSimpleLogin:login", function (event, authUser) {
var query = $firebase(reference.startAt(authUser.uid).endAt(authUser.uid));
query.$on("loaded", function () {
setCurrentUser(query.$getIndex()[0]);
});
});
What is wrong now?
This is an answer on edit 2: I have used firebase(ref), query.$loaded and searched for the right object, that's it. Maybe someone have an different answer, please post them :).
I have finally completed chapter 07!
In general (solution for Edit 2):
$rootScope.$on("$firebaseSimpleLogin:login", function (event, authUser) {
var query = $firebase(reference).$asObject();
query.$loaded(function (result) {
angular.forEach(result, function (key) {
if (key.md5_hash === authUser.md5_hash) {
setCurrentUser(key);
}
});
});
});
This is not the ideal solution, but the free ebook (atm of writing) is far from ideal. Then again, these kind of situations helps you to understand a little bit more about the firebase api and how it works with angular. But can be frustrated at times, when you just want to go through the tutorial ;).
Note! I have saved the User object and pass the User object to the findUsername() and setCurrentUser() functions instead of just the user.username.
You can also use the native array function, like some().
I think your system uses the newer version of Angularfire (version>= 0.8). Which means for running through loops that are arrays ...you need to attach .$asArray() at the end of the user definition field. Check the updates of Firebase.

Specifying Mongo Query Parameters From Client Controller (MEAN.JS)

I am building an application using MongoDB, Angular, Express, and Node (MEAN stack).
I used the MEAN.JS generator to scaffold my application.
I will use the articles module as a reference.
Suppose I have 7000 records in my articles collection, and each record has a date associated with it. It is inefficient to load all 7000 records into memory every time I load the page to view the records in a table and I am seeing terrible performance losses because of it. For this reason, I would only like to load records with a date in the range of (1 Month Ago) to (1 Year From Now) and display them in the table. I can currently do this with the following:
In my articles.client.controller.js:
$scope.find = function() {
$articles = Articles.query();
};
...and in my articles.server.controller.js:
var now = new Date();
var aYearFromNow = new Date(now.getTime() + 86400000*365); //add a year
var aMonthAgo = new Date(now.getTime() - 86400000*30); //subtract roughly a month
exports.list = function(req, res) { Article.find().where('date').lt(aYearFromNow).gt(aMonthAgo).sort('-created').populate('user', 'displayName').exec(function(err, articles) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(articles);
}
});
};
The problem is that this is not a dynamic way of doing things. In other words, I want the user to be able to specify how far back and how far forward they want to see.
How can I bind to variables (e.g. 'aYearFromNow' and 'aMonthAgo') in my client view that will change the query parameters in my server controller?
Another way is to just pass the search parameters in the query method, like this:
$scope.searchart = function() {
Articles.query({start:$scope.startDate, end:$scope.endDate}, function(articles) {
$scope.articles = articles;
});
};
and then at the server side controller, read your query string parameters like this:
exports.searcharticle = function(req, res) {
Article.find().where('date').gt(req.query['start']).lt(req.query['end']).exec(function(err, articles) {
if (err) {
res.render('error', {
status: 500
});
} else {
res.jsonp(articles);
}
});
};
This way doesn't require more routes or services.
It's probably not the cleanest way, but you can create a new service (or edit the current one to work with several parameters):
.factory('ArticlesService2', ['$resource',
function($resource) {
return $resource('articles/:param1/:param2', {
param1: '',
param2: ''
}, {
update: {
method: 'PUT'
}
});
}
]);
Then call it in your controller :
$scope.findWithParams = function() {
$scope.article = ArticlesService2.query({
param1: $scope.aYearFromNow,
param2: $scope.aMonthAgo
});
};
On the back-end, you'll need to prepare a route :
app.route('/articles/:param1/:param2')
.get(articles.listWithParams)
Add a function to your back-end controller :
exports.listWithParams = function(req, res) {
Article.find()
.where('date')
.lt(req.params.param1)
.gt(req.params.param2)
.sort('-created').populate('user', 'displayName')
.exec(function(err, articles) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(articles);
}
});
};
Should work, haven't tested it though.

Sails.js Set model value with value from Callback

i need to provide something like an association in my Model. So I have a Model called Posts with an userid and want to get the username from this username and display it.
So my ForumPosts.js Model looks like the following:
module.exports = {
schema: true,
attributes: {
content: {
type: 'text',
required: true
},
forumTopicId: {
type: 'text',
required: true
},
userId: {
type: 'integer',
required: true
},
getUsername: function(){
User.findOne(this.userId, function foundUser(err, user) {
var username = user.username;
});
console.log(username);
return username;
}
}
};
I know that this return will not work because it is asynchronus... But how can i display it in my view? At the Moment i retrive the value with:
<%= forumPost.getUsername() %>
And for sure get an undefined return...
So the question is: How can I return this value - or is there a better solution than an instanced Model?
Thanks in advance!
Off the top of my head, you can just load associated user asynchronously before rendering:
loadUser: function(done){
var that = this;
User.findOne(this.userId, function foundUser(err, user) {
if ((err)||(!user))
return done(err);
that.user = user;
done(null);
});
}
then in your controller action:
module.exports = {
index: function(req, res) {
// Something yours…
forumPost.loadUser(function(err) {
if (err)
return res.send(err, 500);
return res.view({forumPost: forumPost});
});
}
}
and in your view:
<%= forumPost.user.username %>
This is kind of a quick and dirty way. For a more solid and long-term solution (which is still in development so far) you can check out the alpha of Sails v0.10.0 with the Associations API.
So this particularly case of associations between your models. So here you have a User model and ForumPost model and you need the user object in place of your user_id as user_id works as a relationship mapping field to your User model.
So if your are using sails V0.9.8 or below you need to handle this logic in your controller where ever you want to access User model attributes in your view.
In your controller write your logic as:
model.export = {
//your getForumPosts method
getForumPosts : function(req,res){
var filters = {};
forumPost.find(filters).done(function(err,posts){
if(err) return res.send(500,err);
// Considering only one post obj
posts = posts[0];
postByUser(posts.user_id,function(obj){
if(obj.status)
{
posts.user = obj.msg;
delete posts.user_id;
res.view({post:posts});
}
else
{
res.send(500,obj.msg);
}
});
}
}
}
function postByUser(user_id,cb){
User.findOne(user_id).done(function(err,user){
if(err) return cb({status:false, msg:err});
if(user){
cb({status:true, msg:user});
}
}
}
and then you can access your post object in your view.
Or else you can keep watch (at GitHub) on next version of sails as they have announced associations in V0.10 n it is in beta testing phase as if now.

Categories

Resources