I'm creating an application with ionic and firebase. I'm trying to verify if a element exists in my array, and if it does, I need to return true, else I need to return false. The problem is, it always return false, even if the item exists in firebase. Can you please tell me what is going wrong with following code?
Here's my service:
function IsReserved(id){
var ref = fb.child('/reserved/').orderByChild('product').equalTo(id);
ref.once("value").then(function(snapshot){
snapshot.forEach(function(data){
if(data.val().user === $rootScope.currentUser.$id){
console.log(data.val().user + " * " + $rootScope.currentUser.$id);
return true;
}
});
});
return false;
}
Here is my controller:
function Reservar(produto) {
if(!$rootScope.cart){
$rootScope.cart = [];
$rootScope.fprice = 0;
}
var user=$rootScope.currentUser;
var res = vm.IsReserved(produto.$id);
console.log(res);
if(res){
console.log("já reservado");
return;
}
Here is my firebase strucure:
-reserved:
--KdS2cH1OJ5MhKAV6Yio:
-product: "product1"
-user: "W30BB1RMg1XhNo9og9cMo4Gpr4S2"
Your code won't work because firebase works asynchronously.
You should use a callback function as a parameter, something like this:
function IsReserved(id, callback){
var ref = fb.child('/reserved/').orderByChild('product').equalTo(id);
ref.once("value").then(function(snapshot){
snapshot.forEach(function(data){
if(data.val().user === $rootScope.currentUser.$id){
console.log(data.val().user + " * " + $rootScope.currentUser.$id);
callback(true);
return;
}
});
});
return false; //-- This will always be executed before the code inside the .then, that's why your function always returns false
}
And on you controller, something like this:
function Reservar(produto)
{
if(!$rootScope.cart){
$rootScope.cart = [];
$rootScope.fprice = 0;
}
var user=$rootScope.currentUser;
vm.IsReserved(produto.$id, function(response){
console.log(response);
if(response){
console.log("já reservado");
}
});
}
Could you understand?
Related
I have this code and inside it I set the variable "showLoading" to true to show the user that the page is loading. Sometimes loading takes a long time to finish. How do I set the variable to false again when it finishes loading? Please give me a simple way since ive started coding javascript + angular weeks ago.
HTML inside the table:
<th scope="col" data-toggle="tooltip" title="Organize por data!"
class="table-pointer" ng-click='sortColumn("DATA_VENDA")'
ng-class='sortClass("DATA_VENDA")'>
Data
</th>
SCRIPT:
// column to sort
$scope.column = 'Data';
// sort ordering (Ascending or Descending). Set true for descending
$scope.reverse = false;
// called on header click
$scope.sortColumn = function(col){
$scope.showLoading = false;
$scope.column = col;
if($scope.reverse){
$scope.reverse = false;
$scope.reverseclass = 'arrow-up';
}else{
$scope.reverse = true;
$scope.reverseclass = 'arrow-down';
}
};
// remove and change class
$scope.sortClass = function(col){
if($scope.column == col){
if($scope.reverse){
return 'arrow-down';
}else{
return 'arrow-up';
}
}else{
return '';
}
}
Update
In another part of the code i did this, but i dont know how to apply for the function in the example..
$scope.enjuListBackPecafunction = function() {
$scope.mostrarLoading = true;
return $scope.enjuListBackPeca = Peca.query({
dateFromPeca:'20170101',
dateToPeca:'20180830'
// dateToPeca: $scope.endDate
}, function (err, values) {
$scope.mostrarLoading = false;
if (err) return err;
return values
});
};
Perhaps you want to have a Promise that controls the process that "sometimes takes a long time to finish". Let's imaging there is a method that implements asynchronous sorting:
var doSortAsync = function(column, order) {
return new Promise(function(resolve) {
// ... sending a sort request with column-order params
// ... getting the result asynchronously
// ... and calling the resolve method when it is done
resolve(result);
})
}
Then you just call it in your controller method with appropriate params:
$scope.sortColumn = function(col) {
$scope.showLoading = true;
$scope.column = col;
if($scope.reverse) {
$scope.reverse = false;
$scope.reverseclass = 'arrow-up';
} else {
$scope.reverse = true;
$scope.reverseclass = 'arrow-down';
}
doSortAsync(col, $scope.reverse).then(function(result) {
$scope.showLoading = false;
});
};
You need to know the exact moment when the process is done, and using Promise is a common approach here. In case you can't use ES6 Promises you may try AngularJS $q service.
Use the .finally method of the promise to stop the spinner:
$scope.showLoading = true;
$http.get(url)
.then(function(response) {
$scope.data = response.data;
}).catch(function(response) {
console.log(response.status);
throw response;
}).finally(function() {
$scope.showLoading = false;
});
The .finally block will always execute after the server responds either with the data or an error.
I am quessing that Peca.query is a third-party callback-based API. To integrate it with the AngularJS framework, use $q.defer:
function ajsPecaQuery(options) {
var deferred = $q.defer();
var resource = Peca.query(options, function (err, values) {
if (err) return deferred.reject(err);
//else
return resolve(values);
});
resource.$promise = deferred.promise;
return resource;
}
The function invokes the Peca.query operation and creates an AngularJS promise from the callback. It attaches the promise to the resource object with the property name $promise.
Then use it as so:
$scope.enjuListBackPecafunction = function() {
$scope.mostrarLoading = true;
var resource = ajsPecaQuery({
dateFromPeca:'20170101',
dateToPeca:'20180830'
// dateToPeca: $scope.endDate
});
resource.$promise.finally(function() {
$scope.mostrarLoading = false;
});
return $scope.enjuListBackPeca = resource;
};
The function starts the spinner at the beginning of the operation. It uses the .finally method of the promise to stop the spinner.
Don't forget to inject the $q service.
I've been trying to code up a search engine using angular js, but I can't copy one array to another. When I initiate the the code (in the service.FoundItems in the q.all then function) new array(foundArray) shows up as an empty array. I searched up how to copy one array to another and tried that method as you can see, but it isn't working. Please help, here is the code, and thank you.
P.S. if you need the html please tell me.
(function () {
'use strict';
angular.module('narrowDownMenuApp', [])
.controller('narrowItDownController', narrowItDownController)
.service('MenuSearchService', MenuSearchService)
.directive('searchResult', searchResultDirective);
function searchResultDirective() {
var ddo = {
templateUrl: 'searchResult.html',
scope: {
items: '<'
},
};
return ddo
}
narrowItDownController.$inject = ['MenuSearchService'];
function narrowItDownController(MenuSearchService) {
var menu = this;
menu.input = "";
menu.displayResult = [];
menu.searchX = function(name) {
menu.displayResult = MenuSearchService.FoundItems(menu.input, name);
console.log(menu.displayResult);
};
}
MenuSearchService.$inject = ['$http', '$q'];
function MenuSearchService($http, $q) {
var service = this;
service.getMatchedMenuItems = function(name, searchTerm) {
var deferred = $q.defer();
var foundItems = [];
var result = $http({
method: "GET",
url: ('https://davids-restaurant.herokuapp.com/menu_items.json'),
params: {
category: name
}
}).then(function (result) {
var items = result.data;
for (var i = 0; i < items.menu_items.length; i++) {
if (searchTerm === ""){
deferred.reject("Please enter search term");
i = items.menu_items.length;
}
else if (items.menu_items[i].name.toLowerCase().indexOf(searchTerm.toLowerCase()) ==! -1){
foundItems.push(items.menu_items[i].name)
deferred.resolve(foundItems);
}else {
console.log("doesn't match search");
}
}
});
return deferred.promise;
};
service.FoundItems = function (searchTerm, name) {
var searchResult = service.getMatchedMenuItems(name, searchTerm);
var foundArray = [];
$q.all([searchResult])
.then(function (foundItems) {
foundArray = foundItems[0].slice(0);
foundArray.reverse();
})
.catch(function (errorResponse) {
foundArray.push(errorResponse);
});
console.log(foundArray);
return foundArray;
};
};
})();
If the goal of the service.FoundItems function is to return a reference to an array that is later populated with results from the server, use angular.copy to copy the new array from the server to the existing array:
service.FoundItems = function (searchTerm, name) {
var foundArray = [];
var searchPromise = service.getMatchedMenuItems(name, searchTerm);
foundArray.$promise = searchPromise
.then(function (foundItems) {
angular.copy(foundItems, foundArray);
foundArray.reverse();
return foundArray;
})
.catch(function (errorResponse) {
return $q.reject(errorResponse);
})
.finally(function() {
console.log(foundArray);
});
return foundArray;
};
I recommend that the promise be attached to the array reference as a property named $promise so that it can be used to chain functions that depend on results from the server.
Frankly I don't recommend designing services that return array references that are later populated with results. If you insist on designing it that way, this is how it is done.
I tried the $promise thing that you recommended. I was wondering how you would get the value from it ie the array.
In the controller, use the .then method of the $promise to see the final value of the array:
narrowItDownController.$inject = ['MenuSearchService'];
function narrowItDownController(MenuSearchService) {
var menu = this;
menu.input = "";
menu.displayResult = [];
menu.searchX = function(name) {
menu.displayResult = MenuSearchService.FoundItems(menu.input, name);
̶c̶o̶n̶s̶o̶l̶e̶.̶l̶o̶g̶(̶m̶e̶n̶u̶.̶d̶i̶s̶p̶l̶a̶y̶R̶e̶s̶u̶l̶t̶)̶;̶
menu.displayResult.$promise
.then(function(foundArray) {
console.log(foundArray);
console.log(menu.displayResult);
}).catch(function(errorResponse) {
console.log("ERROR");
console.log(errorResponse);
});
};
}
To see the final result, the console.log needs to be moved inside the .then block of the promise.
Titus is right. The function always immediately returns the initial value of foundArray which is an empty array. The promise is executed asynchronously so by the time you are trying to change foundArray it is too late. You need to return the promise itself and then using .then() to retrieve the value just like you are currently doing inside the method.
From just quickly looking at your code I think you made have a simple error in there. Are you sure you want
foundArray = foundItems[0].slice(0);
instead of
foundArray = foundItems.slice(0);
I want to return data to function that calls a function with firebase code, because of the asynchronous and nested structure of firebase queries it is not able to return values, I intend to use this logic to set tool tips in chart.js
Here is my code:
window.onload = function() {
get_data();
}
function get_data() {
var data = get_val();
console.log("...." + data);
}
function get_val() {
var label = "10/2/2017";
var Name = localStorage.getItem("VName");
console.log("Name:::" + Name);
var at_val;
var dbref = new Firebase("https://apraisalstaging.firebaseio.com/EmployeeDB/EInfo/");
dbref.once("value").then(function(snapshot) {
snapshot.forEach(function(childsnapshot) {
var data = childsnapshot.val();
var Nameval = data.Name;
if (Nameval == Name) {
console.log("Success");
Ikey = childsnapshot.key();
console.log("Key:::" + Ikey);
var dxRef = new Firebase("https://apraisalstaging.firebaseio.com/EmployeeDB/EApraise/" + Ikey);
dxRef.once("value").then(function(snapshot) {
snapshot.forEach(function(childsnapshot) {
var data = childsnapshot.val();
console.log(data);
if (label == data.Dateval) {
console.log("-------> bingo");
at_val = data.Attitude;
console.log("got value:" + at_val);
}
});
}).then(function() {
console.log("In then:" + at_val);
return at_val;
});
}
})
})
}
Data is loaded from the Firebase Database asynchronously. You cannot return a value now that hasn't been loaded yet. And until the async and await keywords are commonplace, you cannot make JavaScript wait for the async value.
The closest you can get today is to return a promise from get_val(). Then your calling code will be:
get_val().then(function(data) {
console.log("...." + data);
});
To do this you'll have to implement get_val() as:
function get_val() {
var label = "10/2/2017";
var Name = localStorage.getItem("VName") || "delta";
console.log("Name:::" + Name);
var at_val;
var dbref = firebase.database().ref("EmployeeDB/EInfo/").orderByChild("Name").equalTo(Name);
return dbref.once("value").then(function(snapshot) {
var promises = [];
snapshot.forEach(function(childsnapshot) {
var data = childsnapshot.val();
var Nameval = data.Name;
Ikey = childsnapshot.key;
var dxRef = firebase.database().ref("EmployeeDB/EApraise/" + Ikey).orderByChild("Dateval").equalTo(label);
promises.push(
dxRef.once("value").then(function(snapshot) {
snapshot.forEach(function(childsnapshot) {
var data = childsnapshot.val();
at_val = data.Attitude;
});
}).then(function() {
console.log("In then:" + at_val);
return at_val;
})
);
})
return Promise.all(promises);
})
}
I made a few changes to get_val():
it uses the new 3.x versions of the Firebase SDK. The solution could also work with 2.x, I just didn't feel like setting up a jsbin for that.
it populates a list of promises, one for each of the EApraise records
it returns a promise that resolves when all the EApraise records are loaded.
it uses Firebase queries to find the correct record. This removes the need for checking the values in the then() callbacks. But more importantly it ensures that only the necessary data is downloaded.
To make that last point true, you need to add a few index definitions to the rules in your Firebase Database console:
{
"rules": {
"EmployeeDB": {
"EInfo": {
".indexOn": "Name"
}
"EApraise": {
"$eid": {
".indexOn": "Dateval"
}
}
}
}
}
Here a jsbin with the working code: http://jsbin.com/jawamilawo/edit?js,console
I am facing following issue:
I am calling in foreach cycle following browse function. When the rb.wsc.browse(symbol) is called the program do some WebSocket request and when the message is returned the event is emmited. The problem is that I always get the same browseData even when I know that the event is emited with different one. I think that this is closure issue, but I don't know how to solve it.
function browse(rb, symbol, callback) {
var result = function(wsc, browseData) {
wsc.off('browse', result);
wsc.off('failed', result);
var err = null;
if (wsc.errno < 0) {
err = new Error("Browsing symbol " + symbol + " failed!");
err.status = wsc.errno;
} else {
saveBrowseData(rb, browseData);
}
callback(err, symbol);
};
// Register temporary listeners
rb.wsc.on('browse', result);
rb.wsc.on('failed', result);
// Browse symbol
rb.wsc.browse(symbol);
}
RexBrowser.prototype.refresh = function() {
var that = this;
var browseRequestNumber = 1;
var browseResult = function(err, symbol) {
browseRequestNumber--;
var item = that.getSymbol(symbol);
_.each(item.children, function(child) {
if (child.browse) {
browseRequestNumber++;
debug("Browsing: " + child.cstring);
browse(that,child.cstring, browseResult);
}
});
if (browseRequestNumber === 0) {
that.emit('refresh', that);
}
};
// Start recursive browsing
browse(this,'$', browseResult);
};-
You could try using a IIFE:
} else {
function(rbInner, browseDataInner){
saveBrowseData(rbInner, browseDataInner);
}(rb, browseData);
}
This makes sure the variables used by / in saveBrowseData have the values they have when the function is called.
I'm new to node.js. I need to display Name in jqgrid, but I stored only id of one document into another document.
Example
I have 2 documents like Student master and student mark document. I have to display mark details in jqgrid. In mark document I stored student id instead of name. How do I fetch the name and send a new object to jqgrid?
My code is as follows:
exports.getAllstudentsmark = function(req, callback)
{
studentsmarks.find(function(error, studentsmarks_collection) {
if( error ) callback(error)
else {
studentsmarks_collection.toArray(function(error, results) {
if( error ) callback(error)
else {
newresult = results;
for(i=0;i<results.length;i++)
{
newresult[i]['studentname'] = getStudentName(results[i].studentid);
}
console.log(newresult);
callback(null, newresult)}
});
}
});
}
var getstudentObjectId = function(id)
{
return student.db.bson_serializer.ObjectID.createFromHexString(id);
}
var getStudentName = function(id)
{
student.findOne({_id: getstudentObjectId (id)}, function(e, o){
console.log(o.name);
return o.name;
});
}
newresult[i]['studentname'] is always getting undefined. But if I log into getStudentName function I can get answer into getStudentName function.
My callback function is only getting this problem. How to resolve and get my result in an easy way. Please help any one.
try this inside your for loop
newresult.push({'studentname': getStudentName(results[i].studentid) });
exlpanation:
by the time you access newresult[i] it doesn't exist, so accessing studentname field of it is impossible
Your problem here is that you are not setting the name of the user into the array, but the return value of student.findOne, since this is an asynchronous method. Maybe try this thing
exports.getAllstudentsmark = function(req, callback)
{
studentsmarks.find(function(error, studentsmarks_collection) {
if( error ) callback(error)
else {
studentsmarks_collection.toArray(function(error, results) {
if( error ) callback(error)
else {
newresult = [];
for(i=0;i<results.length;i++)
{
getStudentName(results[i].studentid, function (studentName) {
newresult.push({studentname: studentName});
})
}
console.log(newresult);
callback(null, newresult)}
});
}
});
}
var getstudentObjectId = function(id)
{
return student.db.bson_serializer.ObjectID.createFromHexString(id);
}
var getStudentName = function(id, callback)
{
student.findOne({_id: getstudentObjectId (id)}, function(e, o){
console.log(o.name);
callback(o.name);
});
}
I hope it helps