Programm flow is behaving abnormal in angularjs - angularjs

I am using angular js mvc ie. ui,controller and service. I have written a code that checks whether the same name organization is present in the database or not.
For this purpose I have written an AJAX call. which return me if the name is present in the database or not in the form of '0' or '1'.
ie.'1' for present and '0' for absent. I check this response in the controller and then if the response is one I am returning false to the calling function, but even though everything goes right I still get to see the variable value as 'undefined'.
Following is the code:
controller:
$scope.checkOrgName = function(){
console.log("We are checking id organization name "+$scope.organization.orgName+" is already present in the database or not");
if($scope.organization.orgName != ""){
OrganizationService.checkOrgName($scope.organization.orgName).then(
function(data){
var dbOrgName = data;
if(dbOrgName==1){
(Command comes here and shows the following alert box on the UI)
$scope.failureAlertMessage("This organization name is already present, enter some other name");
$scope.organization.orgName = "";
return false;(here I am returning false)
}
else if(dbOrgName==0){
console.log("Organization name is available");
return true;
}
},
function(errResponse){
$scope.failureAlertMessage("Error while checking organization name in the database");
}
);
}else{
console.log("No need for the organization name checking, name empty");
}
}
calling function (within controller only)
(Here I am calling the above function)
$scope.orgNameStatus = $scope.checkOrgName();
console.log("$scope.orgNameStatus: "+$scope.orgNameStatus);(This line prints 'undefined')
if($scope.orgNameStatus == false){
return false;
}
Browser Console:
Inside addOrganization
organization_controller.js:51 We are checking id organization name dsd is already present in the database or not
organization_service.js:25 In service: check org name
organization_controller.js:171 $scope.orgNameStatus: undefined
organization_controller.js:217 Validation status: true
organization_controller.js:59 Command in dbOrgName==1
What is wrong with code. Please help me, Thank you.!!

The reason why $scope.orgNameStatus is undefined is that your function $scope.checkOrgNamedoes not return any value. You only have a return statement within the then callback of the function.
In any case, since the function is asynchrounous, it will only return a Promise on which you can register a callback again. You need to make sure that the request is complete before you continue your processing.
Controller
$scope.checkOrgName = function(){
console.log("We are checking id organization name "+$scope.organization.orgName+" is already present in the database or not");
if($scope.organization.orgName != ""){
// added return statement to return promise
return OrganizationService.checkOrgName($scope.organization.orgName).then(
function(data){
var dbOrgName = data;
if(dbOrgName==1){
(Command comes here and shows the following alert box on the UI)
$scope.failureAlertMessage("This organization name is already present, enter some other name");
$scope.organization.orgName = "";
return false;(here I am returning false)
}
else if(dbOrgName==0){
console.log("Organization name is available");
return true;
}
},
function(errResponse){
$scope.failureAlertMessage("Error while checking organization name in the database");
}
);
}else{
console.log("No need for the organization name checking, name empty");
}
}
Calling function
$scope.checkOrgName().then(function(status) {
$scope.orgNameStatus = status; // now the request is complete and we can assign the status to the scope variable
console.log("$scope.orgNameStatus: "+$scope.orgNameStatus);(This line prints 'undefined')
if($scope.orgNameStatus == false){
return false;
}
});

Related

How to handle Angular 2 http update before Continuing

I have a service with an http Post
saveItem(item: Item): Observable<number> {
return this.http
.post(`${this.baseUrl}/items`, item.createJson(), this.getHeaders())
.map(this.getIdFromItem)
.catch(this.handleError);
}
I call this in a save method in my component
save(item: Item): boolean {
if (!this.isValid()) {
return false;
}
this.itemService.saveItem(this.item)
.subscribe(id => {
this.item.id = id;
return true;
},
error => {return false;}
)
}
Within the same component, the user can upload an image related to the item - but I need to save the item before they upload the image.
{
if (!this.save(this.item)) {
alert('You cannot upload an image before saving the item');
return false;
}
The problem is that this.save() doesn't return after the save is complete, but immediately - so my image upload continues (and then fails on the server as it has no Id to associate with it).
I can move the 'isValid' to check before saving - but if the save fails on the server, it's too late.
Do I need to change my save to return an observable and then subscribe to it from my file upload? (if so could you show me some code how to do that?) or do I need to do something to get the value from the Observable before returning from the 'save' method (if so could you show me some code how to do that?)
I know there are other ways of solving this (upload the image anyway and associate it when the item is eventually saved, for example - but I don't like that idea - and I'd like an answer on this as much out of interest as solving this real problem.)
Thanks
the getIdFromItem gets the inserted item's Id from the JSON response - thought it worth mentioning.
You can use a flag that informs the rest of your code if you can upload or not.
service:
saveItem(item: Item): Observable<number> {
return this.http
.post(`${this.baseUrl}/items`, item.createJson(), this.getHeaders())
.map(this.getIdFromItem)
.catch(this.handleError);
}
component:
canUpload: boolean = false;
save(item: Item): void {
this.canUpload = false;
this.itemService.saveItem(this.item)
.subscribe(id => {
this.item.id = id;
this.canUpload = true;
},
error => {return false;}
)
}
upload(): boolean {
if (!this.canUpload) {
console.log('You cannot upload an image before saving the item');
return false;
}
this.canUpload = false;
console.log('You can upload now');
// ...
}

React and Meteor Subscription

I am not sure if this is a limitation to React and Meteors connection as documentation suggests that it should be possible without the extra parameter.
When I call a meteor subscription in react if I do not explicitly state the parameter in the query it returns any data, ignoring the specified data in the publish function.
Meteor.publish("supplier", function() {
if(this.userId) {
var user = Meteor.users.findOne(this.userId, { fields : { active : 1 }});
if(user.active != this.userId || user.active != undefined){
// This only returns 1 singular supplier - is correct
var supplier = Supplier.find({ _id : user.active, users : this.userId });
return supplier;
} else {
return this.ready();
}
} else {
return this.ready();
}
});
Now I call the subscription in react as so
getMeteorData: function () {
var data = {}
handle = Meteor.subscribe("supplier");
if(handle.ready()) {
data.supplier = Supplier.findOne(); // Returns Wrong supplier
//data.supplier = Supplier.findOne({_id: session.get("active")}) // Returns correct supplier
data.supplierReady = true
}
return data;
},
This returns the first supplier in the collection not the one logged in the publish function on the server! However if I explicably pass { _id : user.active} it works!
Now it was my understanding that by doing the logic on the server within the publish function that I could simply use Supplier.findOne() but this is not the case and I don't understand why. Is this a limitation on React/Meteor or am I implementing this wrong?
This isn't a React-specific issue, it's a result of the way findOne works. If you have one or more documents in your client side Supplier collection, Supplier.findOne() will just grab the first record available without reference to the document(s) you just fetched from your subscription.
This means either (a) you have more than one supplier available on the client side due to other preexisting subscriptions, or (b) you are returning more than one supplier from the handle subscription.
Check the state of the client side collection prior to the handle subscription. If there's 1 or more docs and that is the intended state of your application, then modify the client side findOne to add {_id: user.active} as you have before.

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

Ionic registration views

I'm trying to build a registration views, but my problem is that the checking statement if the user is already registered it performs in $ionicPlatform.ready, like the following:
$ionicPlatform.ready(function() {
db = $cordovaSQLite.openDB({ name: "my.db" });
$cordovaSQLite.execute(db, "CREATE TABLE IF NOT EXISTS groups (id integer primary key, title text)");
if (typeof(Storage) != "undefined") {
// Store
var registered = localStorage["isRegistered"];
if(registered == undefined || !registered){
$location.path('/register');
}else{
$location.path('/tab/groups');
}
}
});
The problem that the $urlRouterProvider.otherwise('/tab/groups') preforms before the ionic ready, it means that in the first opening of the application, it appears the groups tab then going to the registration view.
I tried to put the statement check if the user is already registered in the otherwise like the following:
$urlRouterProvider.otherwise(function($injector, $location){
if (typeof(Storage) != "undefined") {
// Store
var registered = localStorage["isRegistered"];
if(registered == undefined || !registered){
$location.path('/register');
}else{
$location.path('/tab/groups');
}
} });
Also, I face another problem that we arrive to the groups tab (getting groups from database) before we open the database in the ionic ready.
Is there any solution to do the registration?
Ionic platform can be used anywhere in the code. You should be able to use
$urlRouterProvider.otherwise(function($injector, $location){
$ionicPlatform.ready(function(){
if (typeof(Storage) != "undefined") {
// Store
var registered = localStorage["isRegistered"];
if(registered == undefined || !registered){
$location.path('/register');
}else{
$location.path('/tab/groups');
}
}
});
});
Also, a state provider may be a better solution

Backbone - check if row returned and loaded to model

I have a model called game. In the router I do:
var game = new models.Game({game_id:game_id,team_id:team_id});
game.fetch({
success: function (data) {
slider.slidePage(new Game({model:data}).$el);
}
});
Then in the Game view I want to determine if the database returned anything. What's the best way to do this? At moment I have:
initialize: function (options) {
if(this.model){
console.log('in the if');
}
else{
console.log('in the else');
}
}
But this will always go into the if even if no row is returned from the database...
Maybe you would want to check for the id property, which in theory only the server should know. (Or, check for a required property like name using Model.has("game_name").)
if(typeof this.model.id != "undefined") {
console.log('in the if');
}
Alternatively, you might want to consider having the server return an HTTP code like "404 not found", to indicate no data. That way, you could be sure that the success callback will always have data, and handle the no-data scenario in the error callback.

Resources