Displaying Toast alert to user based on validation from controller - c

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.

Related

How does Meteor methods return results?

I am using meteor/react for learning facebook graph api.
I want to access users' post on facebook timeline and display them on screen. How can that be done?
With the guidance of the solution provided here [How to perform common FB actions using Meteor?. I have tried the following code: server.js
Meteor.methods({
'seePost' : function(){
var graph=Npm.require('fbgraph');
if(Meteor.user().services.facebook.accessToken){
graph.setAccessToken(Meteor.user().services.facebook.accessToken);
var future = new Future();
var onComplete = future.resolver();
graph.get('/me/feed',function(err,result) {
console.log(result);
return onComplete(err,result);
})
Future.wait(future);
}
else{
return false;
}
}
});
client side code :
Meteor.call("seePost", function(err,result) {
if(err) console.log("error" , err);
else console.log("RES", result);
});
I expect the result displayed in the client side console since I want to show the users the posts on his/er timeline, But I get following output :
RES, undefined
You can do it using await and Meteor.callAsync
Basically the client code waits for the call to complete, and gives you the returned data
const result = await Meteor.callAsync("seePost");
Errors should be handled with a try..catch block
If you use fibers/future, you need to return something with "future".
const future = new Future();
// some code getting result or something
future.return(something);
return future.wait();
this will return something in the callback from client call.
try this code, when you're using fibers you need to "wait" for the response
Meteor.methods({
'seePost': function () {
var graph = Npm.require('fbgraph');
if (Meteor.user().services.facebook.accessToken) {
graph.setAccessToken(Meteor.user().services.facebook.accessToken);
var future = new Future();
var onComplete = future.resolver();
graph.get('/me/feed', function (err, result) {
console.log(result);
if (err) {
return future.return(false);
} else {
return future.return(result);
}
})
return future.wait();
}
return false;
}
});

NativeScript Firebase plugin execution order

I'm learning NativeScript/Angular 2 and would need to get help with this issue.
In order to implement a multi-role login system within the Firebase platform I thought about this solution
Login the user through Firebase authentication
Query the /stores/ path for a store which has a merchantEmail field same as the e-mail that has just logged in
If I find it, I set the store ID inside a BackendService service which uses getString/setString to store tokens, then route to a MerchantDashboardComponent
If I don't find it, just route to a BuyerDashboardComponent
This is part of my code in the login.service:
login (email: string, password: string) {
return firebase.login({
type: firebase.LoginType.PASSWORD,
email: email,
password: password
}).then(
(result: any) => {
firebase.query(
(_result) => { // Here I set BackendService.storeID
Inside the .query() callback I am assigning the tokens I need in the application.
This is the method I'm using in my login.component:
doLogin () {
this.isAuthenticating = true;
if (!this.validateEmail()) {
alert("Please insert a valid email");
return false;
}
this.loginService.login(this.email, this.password).then(
() => {
this.isAuthenticating = false;
if (BackendService.loginError)
alert(BackendService.loginError)
else if (BackendService.storeID != '') {
this.router.navigate(['/merchant-dashboard'], {clearHistory: true});
}
else {
this.router.navigate(['/home/categories'], {clearHistory: true});
}
}
);
}
Everything works except for the fact that the Merchant gets routed to the Buyer dashboard. I've managed to discover that the execution order is not what I expected to be, in fact:
firebase.login() gets executed and returns a Promise
.then() handler is executed inside the doLogin() method
Only after this, the firebase.query() method completes the callback and my tokens are available, but doLogin() has already navigated the user because storeID is still empty when I need it
I hope I've been clear as much as possible.
Thanks for your attention.
Greetings,
Davide
So, the problem was in the login service method.
I now return the Promise generated by firebase.query(), which causes then() calls to chain in the correct order.
Yep that was exactly was I was going to propose to wrap it in a promise and create a chain.
example code
return new Promise<any>((resolve, reject) => {
firebase.login({ loginArguments })
.then((result: any) => {
var onQueryEvent = function (result) {
};
return firebase.query(
onQueryEvent,
"/owner",
{
// query arguments follows here
}
).then(res => {
return res;
})
})
.then(finalResult => {
console.log(finalResult);
try {
resolve(finalResult);
} catch (e) {
reject(e);
}
})
});

Angular + SignalR wait for promise

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");
});

Authentication in Angular 2, handling the observables

I just started with a Angular 2 project and am trying to get authentication up and running. Inspired by this tutorial I decided to do the following:
Create a custom RouterOutlet class (extending it) to handle the authentication logic whenever a url is called.
I succeeded in this custom class, but am still not sure how to check if a user is authenticated. My situation is as follows, I need to query a get call to a external API, for my development proces it is as follows:
getAdmin() {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get('http://localhost:3000/admin/is_admin.json', options)
.map(res => res)
.catch(this.handleError)
}
This API call returns true or false. I was wondering what would be the best option to use this information? Should I for example call the following function each time a URL should be checked?:
isAdmin() {
this.getAdmin().subscribe(
data => this.authenticationResult = data,
error => console.log("Error: ", error),
() => return JSON.parse(this.authenticationResult._data);
}
I can't get this up and running because my observable is undefined when using the function I gave as example.
The "problem" is that your method is asynchronous so you need to be careful the way and when you use it.
If you want to use within the activate method of your custom RouterOutlet, you need to leverage observables and reactive programming.
I don't know exactly the way you want to check admin roles:
activate(instruction: ComponentInstruction) {
return this.userService.getAdmin().flatMap((isAdmin) => {
if (this.userService.isLoggIn()) {
if (this._canActivate(instruction.urlPath, isAdmin) {
return Observable.fromPromise(super.activate(instruction));
} else {
this.router.navigate(['Forbidden']);
return Observable.throw('Forbidden');
}
} else {
this.router.navigate(['Login']);
return Observable.throw('Not authenticated');
}
}).toPromise();
}
_canActivate(url, admin) {
return this.publicRoutes.indexOf(url) !== -1
|| this.userService.isLoggedIn();
}
In order to optimize the request, you could lazily (and only once) call the request to check if the user is admin or not:
isAdmin:boolean;
getAdmin() {
if (this.isAdmin) {
return Observable.of(this.isAdmin);
} else {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get('http://localhost:3000/admin/is_admin.json', options)
.map(res => res)
.catch(this.handleError);
}
}
Another approach will be also to load this hint when authenticating the user. This way, the implementation of the activate method would be simplier:
activate(instruction: ComponentInstruction) {
if (this.userService.isLoggIn()) {
if (this.userService.isAdmin()) {
return super.activate(instruction);
} else if (this._canActivate(instruction.urlPath, isAdmin) {
return super.activate(instruction);
} else {
this.router.navigate(['Forbidden']);
}
} else {
this.router.navigate(['Login']);
}
}
_canActivate(url, admin) {
return this.publicRoutes.indexOf(url) !== -1
|| this.userService.isLoggedIn();
}
I would consider to call getAdmin() somehow as first Step of your app, store the result in a SessionService object which you move around using Dependency Injection. This way any time you need to check the result of getAdmin you can ask the SessionService instance.
I hope this helps

Angular service and pouchdb

How do you use angularjs service to call pouchdb and return the data to the controller? I have been working on a ionic app with pouchdb for local storage. I have a simple crud app built in a controller. Now I want to start to move the pouchdb calls into a service. I haven’t been able to get back data from the service. How would I use a service to call pouchdb to get all docs and return it to the controller?
One strategy that I think could work very well for Angular services is this one. It describes a method for keeping an in-memory array synced with the result of PouchDB's allDocs().
Since it's an array that automatically stays synced with PouchDB, you can just do an ng-repeat on it, and you're done. :)
Although your question is a year old, it deserves an answer.
You might want more than one service i.e. one to use in the controller and another for the backend database storage. For example, in the controller:
(function () {
'use strict';
angular
.module('app.services')
.factory('db',db);
db.$inject = ['$db'];
function db($db) {
var data = {}; // set up a data object to receive document(s)
return {
getDoc: getDoc,
getList: getList,
save: save,
saveBatch: saveBatch
};
// get a single document using the id
function getDoc(id) {
$db.getDoc(id)
.then(
function onSuccess(doc) {
// success so update the view model
angular.extend(data,doc); // use angular.extend to shallow copy object so that it can be returned in full
},
function onError() {
// failure to get document
}
);
return data;
}
// retrieve a group of documents where key is the prefix of the data you want
function getList(key) {
$db.getList(key).then(
function onSuccess(docs) {
// success so update the view model details
angular.forEach(docs.rows, function (value) {
this.push(value.doc);
}, data);
// now you can sort data or anything else you want to do with it
},
function onError() {
// no data found
}
);
return data;
}
// save a single viewItem
function save(viewItem) {
$db.update(viewItem).then(
function onSuccess() {
// success so update view model if required
},
function onError(e) {
console.log(e); // unable to save
}
);
}
// save an array of viewItems
function saveBatch(viewItems) {
$db.updateBatch(viewItems).then(
function onSuccess() {
// success so update the view model if required
},
function onError(e) {
console.log(e); // unable to save
}
);
}
}
})();
For the backend, something like this:
(function () {
'use strict';
angular
.module('app.services')
.factory('$db',$db);
$db.$inject = ['$q'];
function $db($q) {
var db;
return {
setLocalDB: setLocalDB,
update: update,
updateBatch: updateBatch,
getDoc: getDoc,
getAllDocs: getAllDocs,
getList: getList
};
// ------ DATABASE OPENING HANDLER(S) ------
// set to any named database
function setLocalDB(dbName) {
db = new PouchDB(dbName);
return db.info()
.catch(failedCheck()); // returns a promise to either work or fail
}
// return a rejection for a failure
function failedCheck() {
return $q.reject();
}
// ------ DOCUMENT HANDLING ------
// update document but if errors occur recurse qUpdate until either complete or retries exhausted
function update(doc) {
var counter = 0;
return $q.when(qUpdate(doc,counter));
}
// this routine works for both new and existing documents
function qUpdate(doc,counter) {
return db.put(doc)
.then(function() {
console.log('success - new document');
})
.catch(function(e) {
console.log(e); // not a new document so try as a revision of existing document using _id to find
return db.get(doc._id)
.then(function(origDoc) {
doc._rev = origDoc._rev; // get document revision _rev
return db.put(doc,doc._id,doc._rev)
.then(function() {
console.log('success - revision of document');
})
.catch(function(e){
console.log(e); // log error for failure
});
})
.catch(function(e){
console.log(e); // log error before we take any other action
counter ++; // increment counter, so we can limit retries (5 by default)
if (counter< 5) {
switch (e.status) {
case 404:
delete doc._rev; // remove revision information so we can see if this works
return qUpdate(doc); // might be deleted so return revised document for retry
case 409:
return qUpdate(doc); // in conflict so try again
default:
try {
throw new Error("cannot save: " + doc._id); // cannot go any further so throw new error
} catch(err) {
console.log(err); // log error for failure
}
}
} else {
try {
throw new Error("cannot save" + doc._id); // cannot go any further so throw new error
} catch(err) {
console.log(err); // log error for failure
}
}
});
});
}
// update a document batch stored in an array
function updateBatch(docs) {
return $q.when(qUpdateBatch(docs));
}
// do the actual update of a batch
function qUpdateBatch(docs) {
db.bulkDocs(docs).then(function(res) {
for (var i=0; i < res.length; i++) {
if (res[i].status === 409) {
update(docs[i]); // in conflict so try this document separately
}
}
}).catch(function(e){
console.log(e); // log error
});
}
// get the document as an angular promise and deal with it in host routine
function getDoc(id) {
return $q.when(db.get(id));
}
// get all documents
function getAllDocs() {
return $q.when(db.allDocs({include_docs: true, attachments: false}));
}
// get a batch of documents between a start and end key
function getList(key) {
return $q.when(db.allDocs({startkey: key, endkey: key + '\uffff', include_docs: true, attachments: false}));
}
}
})();
In your main controller you would want to set the database:
$db.setLocalDB('yourDB');
Hope this is what you were looking for?
In my own data services module I have other functions for remote database, event listeners, remove, sync, compact, destroy and so on.

Resources