Angular + SignalR wait for promise - angularjs

I have list of users for chat purpose, something like on facebook where i got all users from my database using ngResource. When user is offline i got red marker close to his name and when is online i use green marker.
What i want to archieve is that when user sign in, my red marker will turn into green. When user login into my app, my Hub method OnConnected() gets fired and call my client side code
Hub method when user sign in.
#region Connect
public override Task OnConnected()
{
var userDetails = new ApplicationUser
{
ConnectionId = Context.ConnectionId,
UserName = Context.Request.GetHttpContext().User.Identity.Name,
Id = HttpContext.Current.User.Identity.GetUserId(),
};
if (onlineUsers.Count(x => x.ConnectionId == userDetails.ConnectionId) == 0)
{
onlineUsers.Add(new ApplicationUser {
ConnectionId = Context.ConnectionId,
UserName = userDetails.UserName,
Id = userDetails.Id,
});
Clients.All.newOnlineUser(userDetails);
Clients.Caller.getOnlineUsers(onlineUsers);
}
return base.OnConnected();
}
#endregion
Client side code in my controller
$scope.online_users = UserService.getChatUsers();
PrivateChatService.addOnlineUser(function (user) {
angular.forEach($scope.online_users, function (value, key) {
if (user.UserId == value.Id) {
value.Active = true;
}
});
console.log("newOnlineUser finished");
});
Problem is with forEach method in my client side code. In that time when my signalR hub fires my method ".addOnlineUser" my $scope.online_users is not resolved so i only have promise but not data so i cant iterate through that array to change user status from offline to online. Is something how i can wait for promise to be resolved?
Update:
I had something like this but this is not definitely good aproach since i hit all the time my database to get users.`
PrivateChatService.addOnlineUser(function (user) {
var dataPromise = UserService.getChatUsers(function(response){
$scope.online_users = response;
angular.forEach(dataPromise, function (value, key) {
if (user.UserId == value.Id) {
value.Active = true;
}
});
});
console.log("newOnlineUser finished");
});

Related

Displaying Toast alert to user based on validation from controller

I am trying to see what would be the best way to approach this. I am using MVC .Net Core Web App.
When a user clicks a "Create Ticket" button, it checks to see how many tickets are open. If more than 5 tickets are open, then display toast alert message. If not, then create ticket.
public IActionResult Create()
{
var ticket = _context.tickets
.where(x => x.statusID == "1") //1 = open
if(ticket.Count() > 5){
//from my research many people use tempData here
TempData["Alert"] = "You have exceeded limit"
return ? //What do I return???
}
Ticket ticket = new Ticket();
_context.ticket.Add(ticket);
_context.ticket.SaveChanges();
return RedirectToAction("Index");
}
I want to display the alert without refreshing the page. Will the best approach be to do an Ajax call when button is clicked? If so, would it look like this
$(function () {
$("#Createbtn").click(function (e) {
e.preventDefault();
$.ajax({
cache: false,
type: "GET",
url: "/Tickets/CreateValidation",
datatype: "json",
success: function (data) {
alert(data);
},
})
})
})
Then from the action I can redirect to "Create" action?
I appreciate the input. Thanks.
As far as I know, if you want to return message to the client ajax success function, you should return OKresult in your controller method.
Besides, since you use ajax to call the method function, it will return the index html makeup instead of redirect to the index method when you call RedirectToAction.
In my opinion, you should check the message in the client success function. If the return message is a url, you should use window.location.href to redirect to the returned url.
Details, you could refer to below codes:
[Route("Tickets/CreateValidation")]
public IActionResult Create()
{
// var ticket = _context.tickets
// .where(x => x.statusID == "1") //1 = open
//if (ticket.Count() > 5)
// {
// //from my research many people use tempData here
// TempData["Alert"] = "You have exceeded limit"
// return ? //What do I return???
// }
// Ticket ticket = new Ticket();
// _context.ticket.Add(ticket);
// _context.ticket.SaveChanges();
// return RedirectToAction("Index");
//I don't have your dbcontext, so I create a ticket number directly
var ticketnumber = 4;
if (ticketnumber >5)
{
//If we want to return string to the client side inside a post action method, we could directly using OK or Json as the result.
//If we use OK to return data, the we could receive this data inside the ajax success method
return Ok("You have exceeded limit");
}
return Ok("/Default/Index");
}
Client-side ajax:
$(function () {
$("#Createbtn").click(function (e) {
e.preventDefault();
$.ajax({
cache: false,
type: "GET",
url: "/Tickets/CreateValidation",
datatype: "json",
success: function (data) {
if (data == "/Default/Index") {
window.location.href = data;
} else {
alert(data);
}
}
})
})
})
</script>
Result:
If the ticket number > 5:
If the ticket number <5:
You could find the page has refreshed.

Maintaining a Session in MVC .net application using angularjs

I am working on an application, in which a user if has an account in db can log in the website and then perform certain functions. One of those functions involve creating a blog. The blog is being displayed in another project application using the same database. Now when user creates a blog after logging in, i need to store who created the blog in order to do that, i came up with 2 ways. Either i keep passing the user id as a parameter on every page url or i can create a session in order to store it for the duration of login.
I think the latter is a better option but i am kind of lost on how to do it. I am creating a 3 project layer Application. with the client side done in angularjs. My c# controller is being used just to pass the json data to another layer, which then communicates with the database which is in another layer.
The project files are too big but i can write a example code for it.
Html:
<div ng-app="Module">
<div ng-controller="AppController">
<input ng-model="user.Email" type="email"\>
<button type="button" ng-click="UserLogin()"\>
</div>
</div>
AngualrJs:
var app = angular.module('Module', []);
app.controller("AppController", function ($scope) {
$scope.loginchk = function () {
Post("/User/LoginValidation", $scope.user, false, $("#btnlogin")).then(function (d) {
if (d.Success) {
window.location.href = "/User/LoggedIn?emailId=" + $scope.user.Email;
}
ShowMessage(d);
});
}
})
Controller:
public JsonResult LoginValidation(LoginUser user) {
return Json((new userLogic()).LoginChk(user), JsonRequestBehavior.AllowGet);
}
Business Logic LAYER----------------
UserLogic:
public Message LoginChk(LoginUser user) {
Message msg = new Message();
try {
Account userProfile = db.Accounts.Where(b => b.Email == user.Email).FirstOrDefault();
if (userProfile == null)
{
msg.Success = false;
msg.MessageDetail = "Account Email does not exist";
}
else
{
if (userProfile.password != user.Password)
{
msg.Success = false;
msg.MessageDetail = "Wrong Password";
}
else
{
msg.Success = true;
msg.MessageDetail = "Logged In";
}
}
}
catch(Exception ex)
{
msg.Success = false;
msg.MessageDetail = "DB connection failed.";
}
return msg;
}
Now I know i can create a Session Variable in the controller like this Session['Sessionname'] = user;
but i am not sure it will work with my application because i have multiple controllers and i will still have to pass it to them. so i dont see the point of maintaining a session variable in every controller even if its not used. How do i go about creating a session?
local storage is best option to do that :
window.localStorage.setItem("userId",useId);
to get again:
localStorage.getItem("userId");
You Can use client-side LocalStorage to save the user-id and use it where ever necessary,
as it will be saved in plain text you can encrypt and save it .
check here how to encrypt using javascript
https://stackoverflow.com/a/40478682/7262120

Link Sails's authenticated user to websocket's user

I am currently trying to create an sails+angular web-app.
I already have a user-authentication system working (based on this tutorial : https://github.com/balderdashy/activity-overlord-2-preview). I am trying to integrate a very simple chat inside using websocket.
My issue is to link websocket's "user" to the authenticated user.
Because when an authenticated user writes a message, I want to send the message as data but not the id of the current user, i would like to get this id from the sail's controller.
This is my actual sails chatController :
module.exports = {
addmsg:function (req,res) {
var data_from_client = req.params.all();
if(req.isSocket && req.method === 'GET'){
// will be used later
}
else if(req.isSocket && req.method === 'POST'){
var socketId = sails.sockets.getId(req);
/* Chat.create(data_from_client)
.exec(function(error,data_from_client){
console.log(data_from_client);
Chat.publishCreate({message : data_from_client.message , user:currentuser});
}); */
}
else if(req.isSocket){
console.log( 'User subscribed to ' + req.socket.id );
}
}
}
and this is my angular's controller
io.socket.get('http://localhost:1337/chat/addmsg');
$scope.sendMsg = function(){
io.socket.post('http://localhost:1337/chat/addmsg',{message: $scope.chatMessage});
};
req.session.me
...was the solution.

Firebase: How can i use onDisconnect during logout?

How can i detect when a user logs out of firebase (either facebook, google or password) and trigger the onDisconnect method in the firebase presence system. .unauth() is not working. I would like to show a users online and offline status when they login and out, minimize the app (idle) - not just when the power off their device and remove the app from active applications on the device.
I'm using firebase simple login for angularjs/ angularfire
Im using code based off of this tutorial on the firebase site.
https://www.firebase.com/blog/2013-06-17-howto-build-a-presence-system.html
Please i need help with this!
Presence code:
var connectedRef = new Firebase(fb_connections);
var presenceRef = new Firebase(fb_url + 'presence/');
var presenceUserRef = new Firebase(fb_url + 'presence/'+ userID + '/status');
var currentUserPresenceRef = new Firebase(fb_url + 'users/'+ userID + '/status');
connectedRef.on("value", function(isOnline) {
if (isOnline.val()) {
// If we lose our internet connection, we want ourselves removed from the list.
presenceUserRef.onDisconnect().remove();
currentUserPresenceRef.onDisconnect().set("<span class='balanced'>☆</span>");
// Set our initial online status.
presenceUserRef.set("<span class='balanced'>★</span>");
currentUserPresenceRef.set("<span class='balanced'>★</span>");
}
});
Logout function:
var ref = new Firebase(fb_url);
var usersRef = ref.child('users');
service.logout = function(loginData) {
ref.unauth();
//Firebase.goOffline(); //not working
loggedIn = false;
seedUser = {};
clearLoginFromStorage();
saveLoginToStorage();
auth.logout();
};
The onDisconnect() code that you provide, will run automatically on the Firebase servers when the connection to the client is lost. To force the client to disconnect, you can call Firebase.goOffline().
Note that calling unauth() will simply sign the user out from the Firebase connection. It does not disconnect, since there might be data that the user still has access to.
Update
This works for me:
var fb_url = 'https://yours.firebaseio.com/';
var ref = new Firebase(fb_url);
function connect() {
Firebase.goOnline();
ref.authAnonymously(function(error, authData) {
if (!error) {
ref.child(authData.uid).set(true);
ref.child(authData.uid).onDisconnect().remove();
}
});
setTimeout(disconnect, 5000);
}
function disconnect() {
ref.unauth();
Firebase.goOffline();
setTimeout(connect, 5000);
}
connect();

How to update user field in angular-meteor?

I've configured all users to be created with an empty favorites array: user.favorites: []
Since the users collection is treated differently, how should I publish, subscribe, and access subscribed favorites data in angular-meteor?
Here's what I have so far:
// Meteor.methods ==========================================
addFavorite: function(attendeeId){
var loggedInUser = Meteor.user();
if( !loggedInUser ){
throw new Meteor.Error("must be logged in");
}
loggedInUser.favorites.push(attendeeId);
loggedInUser.username = loggedInUser.username+"x";
console.log(loggedInUser.favorites);
}
// controller ========================================
$scope.addFavorite = function(attendeeId){
$meteor.call("addFavorite", attendeeId);
}
// server =======================================================
Meteor.publish('myFavorites', function(){
if(!this.userId) return null;
return Meteor.users.find(this.userId);
});
Meteor.users.allow({
insert: function(userId, doc){
return true;
},
update: function(useId, doc, fieldNames, modifier){
return true;
},
remove: function(userId, doc){
return true;
}
});
User.favorites is empty. When addFavorite is called, it logs an array with a single userId that doesn't update the mongoDB at all. It looks as if Meteor.user() isn't reactivly updating. Does anyone know what I'm doing wrong? Thank you!
EDIT
Latest iteration of code. Favorites are passed into $scope.favorites but isn't reactive. How do I fix this? Thanks!
// publish
Meteor.publish('myFavorites', function(){
if(this.userId){
return Meteor.users.find(this.userId, {
fields: {
favorites: 1
}
});
}else{
this.ready();
}
});
// subscribe
$meteor.subscribe('myFavorites')
.then(function(subscriptionHandle)
{
var user = $meteor.collection(function(){
return Meteor.users.find({_id: Meteor.userId()});
});
$scope.favorites = user[0].favorites;
});
tldr;
Accounts collection is reactive, but by default only the username, emails, and profile fields are published. The quickest fix is to attach the favorites as a new field on the User.profile object.
// Meteor.methods ==========================================
addFavorite: function(attendeeId){
var loggedInUser = Meteor.user();
if( !loggedInUser ){
throw new Meteor.Error("must be logged in");
}
if (loggedInUser.profile.favorites){
loggedInUser.profile.favorites.push(attendeeId);
}
else {
loggedInUser.profile.favorites = [];
loggedInUser.profile.favorites.push(attendeeId);
}
loggedInUser.username = loggedInUser.username+"x";
console.log(loggedInUser.profile.favorites);
}
Although right now you probably are writing to the user, which you can verify by using meteor mongo --> db.users.find().pretty(), but the subscription does not publish your favorites field.
Alternative approach
Alternatively, you can publish the favorites field
// Server code --------
Meteor.publish("userData", function () {
if (this.userId) {
return Meteor.users.find({_id: this.userId},
{fields: {'favorites': 1}});
} else {
this.ready();
}
});
Opinionated Meteor.users philosophy
I like to structure my users object around 3 properties:
User.profile --> published to the client, and directly modifiable by the client through client-side code
User.public --> published to the client, but not modifiable except through server-side Meteor methods
User.private --> not published to the client (i.e. only accessible to read on server code), and only modifiable by server code (with client simulation)
Just make sure that when you remove the insecure and autopublish packages that you double-check your Collections security by using the Meteor.users.allow() function in your server code
Run meteor list to if you want to verify whether or not insecure and autopublish packages are being used in your current project. NOTE: By default Meteor does install them when you first create your app)
// Server code --------
Meteor.publish("userData", function () {
if (this.userId) {
return Meteor.users.find({_id: this.userId},
{fields: {'public': 1}});
} else {
this.ready();
}
});

Resources