问题
i'm trying to build a simple app using meanjs. i have 2 modules: the standard user module and a posts module. what i want to achieve is a user profile page which will display some info about particular user and list posts belong to that user. you can think of it as a twitter profile page. i thought it would also be best /users/username shaped url structure. but i'm fairly new on all this and now stuck. here is what i did so far:
i added these lines into users.server.routes.js:
app.route('/api/users/:userName').get(users.userByUsername);
app.param('userName', users.userByUsername);
added a function to server control like this:
exports.userByUsername = function(req, res, next, username) {
User.findOne({
username: username
}).exec(function(err, user) {
if (err) return next(err);
if (!user) return next(new Error('Failed to load User ' + username));
req.profile = user;
next();
});
};
i added this part to users.client.routes.js
state('view.profile', {
url: '/users/:username',
templateUrl: 'modules/users/views/view-profile.client.view.html'
});
i created a new view like this:
<section class="row" data-ng-controller="ViewProfileController" ng-init="findUser()">
<div class="col-xs-offset-1 col-xs-10 col-md-offset-4 col-md-4">
...
</div>
</section>
and finally i created a new client controller:
angular.module('users').controller('ViewProfileController', ['$scope', '$http', '$stateParams', '$location', 'Users', 'Authentication',
function($scope, $http, $location, Users, Authentication, $stateParams) {
$scope.user = Authentication.user;
$scope.findUser = function () {
$scope.ourUser = Users.get({
username: $stateParams.username
});
};
}
]);
when i try to open users/username page for any username, it just gives the main homepage to me. any ideas what is wrong or what is missing? thanks in advance.
回答1:
I finally figured it out and I'd like to put solution here in detail. I'm not sure this is the best way, but this is how I did. Any suggestions are welcome. Let's start.
Since we want to use .../user/username
URL structure, we first need to add these lines to users.server.route.js
file.
app.route('/api/users/:username').get(users.read);
app.param('username', users.userByUsername);
Now we have to add our userByUsername
middleware into users.profile.server.controller.js
:
/*
* user middleware
* */
exports.userByUsername = function(req, res, next, username) {
User.findOne({
username: username
}, '_id displayName username created profileImageURL tagLine').exec(function(err, user) {
if (err) return next(err);
if (!user) return next(new Error('Failed to load User ' + username));
req.user = user;
next();
});
};
You may have not tagLine
field in your collection, or you may have other custom fields. So remember to change that part and include or exclude desired fields. Never leave empty that part. Because, you wouldn't want to get all user information, including e-mail, password hash etc for security reasons. Any signed in user can reach this information, just by knowing username.
At this point when we type .../api/users/username
in the address bar of our browser, we must get the correct json. This is good, but we also want to get posts belong to this user. So we need to do something like this for the posts.
I added this line to posts.server.routes.js
:
app.route('/api/posts/of/:userid').get(posts.listOf);
... and this part to posts.server.controller.js
:
exports.listOf = function(req, res) { Post.find( { user: req.params.userid }).sort('-created').exec(function(err, posts) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(posts);
}
});
};
Now when you type .../api/posts/of/userid
in your address bar, you must get correct json of posts of userid.
So the next step is do the client side job, and connect to REST endpoints.
Open users.client.routes.js
and add this:
state('users', {
url: '/users/:username',
templateUrl: 'modules/users/views/view-profile.client.view.html'
});
Template Url points to newly created html file which I want to use for user profile page. So create this file under client/views
folder:
<div class="col-md-12" data-ng-controller="ViewProfileController" data-ng-init="findUser()">
...
{{ ourUser }}
<hr />
{{ userPosts }}
....
You can fill this file as you like. I created a new controller for this view. As you can see its name is ViewProfileController
. And I have a findUser
function to do the job. Here is the controller code:
'use strict';
angular.module('users').controller('ViewProfileController', ['$scope', '$http', '$location', 'Users', 'Authentication', '$stateParams',
function($scope, $http, $location, Users, Authentication, $stateParams) {
$scope.user = Authentication.user;
$scope.findUser = function () {
$scope.ourUser = Users.get({
username: $stateParams.username
}).$promise.then( function(ourUser) {
var userPostsPromise = $http.get('api/posts/of/' + ourUser._id);
userPostsPromise.success(function(data) {
$scope.userPosts=data;
$scope.ourUser=ourUser;
});
userPostsPromise.error(function() {
alert('Something wrong!');
});
}
);
};
}
]);
I didn't create a new angular route for posts. As you can see I used an AJAX request to pull the posts. I've considered other options, such as creating a directive etc. In the end, I find this way most comfortable.
That's all. Now you can open your view file, view-profile.client.view
and start to decorate. You can reach ourUser
and userPosts
there. And the URL of this profile page is: .../users/username
.
I hope this helps.
来源:https://stackoverflow.com/questions/28631006/meanjs-user-profile-functionality