Calling mongodb insert,find functions from another class in react native , returns undefined - mongodb

This is my first class where I defined all db functions.
import React,{Component} from 'react';
var Datastore = require('react-native-local-mongodb')
, db = new Datastore({ filename: 'asyncStorageKey', autoload: true });
export default class RDDBManager {
static dbmanager = null;
static getInstance() {
if (RDDBManager.dbmanager == null) {
RDDBManager.dbmanager = new RDDBManager();
}
return this.dbmanager;
}
constructor () {
}
//insert items
insertItem(item){
var json = item.toJsonString();
console.log("Inside insertItem ::: "+json);
db.insert(json,function(err,newDos){
return newDos;
});
}
//read single item
readItem(itemId){
db.findOne({ id: itemId }, function (err, doc) {
return doc;
});
}
//read all items
readAllItems(){
db.find({}, function (err, docs) {
return docs;
});
}
getModalData(modalName) {
this.readAllItems();
}
//update
updateItem(itemId){
db.update({ id: itemId }, { $set: { system: 'solar system' } }, { multi: true }, function (err, numReplaced) {
});
}
//delete item
deleteItem(itemId){
db.remove({ id: itemId }, {}, function (err, numRemoved) {
return numRemoved;
});
}
}
But,when I try to call these functions from another class,the data is undefined.
loadDataFromDB() {
var items = RDDBManager.getInstance().readAllItems();
console.log("Items ======>>>>>> "+items);
}
the value of items is undefined.

This is because you are not doing things right, Your readallitems is async in nature so you have to do something like this:-
//read all items
readAllItems(callback){
db.find({}, function (err, docs) {
callback(docs);
});
}
And For calling something like this:-
loadDataFromDB() {
RDDBManager.getInstance().readAllItems(function(items){
console.log("Items ======>>>>>> "+items);
});
}
Alternatively, you can use promise or Async await also.

Related

Waterline ORM assign the result of find to a variable

I want to combine the results of 2 queries and then return them as one, like this:
test: async (req, res) => {
const valOne = TableOne.find({ id: id })
.exec((err, result) => {
if (err) {
res.serverError(err);
}
return result;
});
const valTwo = TableTwo.find({ id: id })
.exec((err, result) => {
if (err) {
res.serverError(err);
}
return result;
});
const data = {
keyOne: valOne,
keyTwo: valTwo,
};
res.json(data);
}
I understand above code won't return because it's async. How can I achieve this?
There is not much info you supply: node version, sails version, etc.
There are several approaches here:
1. Using promises
2. Using callback chaining
3. Using await/async
If you use sails 1.0 and node >= 8, your best bet is to use await/async, so your code should work like that:
test: async (req, res) => {
let valOne, valTwo;
try {
valOne = await TableOne.find({ id: id });
valTwo = await TableTwo.find({ id: id });
} catch (err) {
return res.serverError(err); //or res.badRequest(err);
}
const data = {
keyOne: valOne,
keyTwo: valTwo,
};
res.json(data);
}

how do i show ionic loading until local storage is populated in pouch

I have used service for storing data in local storage using pouchDB. I would like to show ionic loading until the data are downloaded and stored locally. For now I have used timeout which is not an option for me.
My Service
function populateLocaldb() {
var count;
_localdb.info().then(function(d){
console.log(d.doc_count)
count = d.doc_count;
if(count===0) {
populateData1();
populateData2();
populateData3();
} else {
}
});
}
function populateChapter() {
$http.get('http://....').success(function(data) {
//console.log(data)
var values= data;
for(var i=0; i<values.length; i++) {
var value= {
_id: values[i].ID,
title: chapters[i].Title
}
_localdb.put(value, function callback(err, result) {
if (!err) {
console.log('Successfully posted a value!');
}
});
}
})
}
Controller
dbService.getAllinfo().then(function(data) {
if(data == ""){
//do nothing
//alert(" null Alert hello")
console.log(data)
$ionicLoading.show({
content: 'Loading',
animation: 'fade-in',
showBackdrop: true,
maxWidth: 200,
showDelay: 0
}).then(function() {
dbService.populateLocaldb();
});
} else {
//do nothing
}
})
$timeout(function () {
$ionicLoading.hide();
}, 50000);
It looks like you might need to call $scope.$apply() in the PouchDB callback. Also, another tip: instead of doing multiple put()s inside of a forEach(), it's more efficient in PouchDB to do a single bulkDocs() operation.

Protractor specs leaking

I'm still quite new to promises and the like and I need some help with this problem. One of my it blocks does not end before the next one begins ending up in a StaleElementReferenceError a whole specfile later from where the code was supposed to be called.
listView.js (I know it looks weird but I set it up this way for an unrelated reason):
module.exports = function () {
var public = {};
public.checkFilters = function (filters) {
var promises = [];
for (var i = 0; i < filters.length; i++) {
promises[i] = getFilterPromise(filters[i]);
}
return protractor.promise.all(promises);
};
var getFilterPromise = function (filter) {
return public.getHeaderIndex(filter.on).then(function (headerIndex) {
return checkRows(filter.values, headerIndex);
});
};
public.getHeaderIndex = function (text) {
var headers = table.all(by.tagName('th'));
var correctHeaderIndex;
return headers.each(function (header, index) {
header.getText().then(function (actualHeaderText) {
if (actualHeaderText === text) {
correctHeaderIndex = index;
}
})
}).then(function () {
return new Promise(function (resolve, reject) {
if (correctHeaderIndex) {
resolve(correctHeaderIndex);
} else {
reject('Header not found');
}
});
});
};
public.getWorkflowCount = function () {
return workflows.count();
};
var checkRows = function (matchers, headerIndex) {
var mismatch = false;
return workflows.each(function (element, index) {
public.getTextFromCell(index, headerIndex).then(function (actual) {
if (!anyMatch(actual, matchers)) {
mismatch = true;
}
});
}).then(function () {
return new Promise(function (resolve, reject) {
if (mismatch) {
reject('Header not found');
} else {
resolve('all rows matched');
}
});
});
};
var anyMatch = function (actual, matchers) {
var match = false;
for (var j = 0; j < values.length; j++) {
if (text === values[j]) {
match = true;
}
}
return match;
};
public.getTextFromCell = function (row, column) {
return workflows.get(row).all(by.tagName('td')).get(column).getText();
};
return public;
}();
LV_00:
describe('LV_00:', function () {
it('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress);
});
it('statusfilter works', function () {
P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
I think you should move the test preparation code into the beforeEach():
describe('LV_00:', function () {
beforeEach('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress);
});
it('statusfilter works', function () {
P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
You may also need to use the done callback function:
describe('LV_00:', function (done) {
beforeEach('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress).then(function () {
done();
});
});
it('statusfilter works', function () {
P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
assuming filter() returns a promise.
Found the solution thanks to alecxe proposing to use done() I used the following after some googling around.
it('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress);
});
it('statusfilter works', function () {
protractor.promise.controlFlow().execute(function () {
return P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
Found here: Prevent Protractor from finishing before promise has been resolved

Using design documents in pouchDB with crypto-pouch

After testing pouchDB for my Ionic project, I tried to encrypt my data with crypto-pouch. But I have a problem with using design documents. I used the following code:
One of my design documents:
var allTypeOne = {
_id: '_design/all_TypeOne',
views: {
'alle_TypeOne': {
map: function (doc) {
if (doc.type === 'type_one') {
emit(doc._id);
}
}.toString()
}
}
};
For init my database:
function initDB() {
_db = new PouchDB('myDatabase', {adapter: 'websql'});
if (!_db.adapter) {
_db = new PouchDB('myDatabase');
}
return _db.crypto(password)
.then(function(){
return _db;
});
// add a design document
_db.put(allTypeOne).then(function (info) {
}).catch(function (err) {
}
}
To get all documents of type_one:
function getAllData {
if (!_data) {
return $q.when(_db.query('all_TypeOne', { include_docs: true}))
.then(function(docs) {
_data = docs.rows.map(function(row) {
return row.doc;
});
_db.changes({ live: true, since: 'now', include_docs: true})
.on('change', onDatabaseChange);
return _data;
});
} else {
return $q.when(_data);
}
}
This code works without using crypto-pouch well, but if I insert the _db.crypto(...) no data is shown in my list. Can anyone help me? Thanks in advance!
I'm guessing that your put is happening before the call to crypto has finished. Remember, javascript is asynchronous. So wait for the crypto call to finish before putting your design doc. And then use a callback to access your database after it's all finished. Something like the following:
function initDB(options) {
_db = new PouchDB('myDatabase', {adapter: 'websql'});
if (!_db.adapter) {
_db = new PouchDB('myDatabase');
}
_db.crypto(password)
.then(function(){
// add a design document
_db.put(allTypeOne).then(function (info) {
options.success(_db);
})
.catch(function (err) { console.error(err); options.error(err)})
.catch(function (err) { console.error(err); options.error(err);})
}
}
initDB({
success:function(db){
db.query....
}
)

smart way to rewrite this function

I have this, and I am showing a div if user clicked one button and not showing it if the user clicked other. Its working but its dumb to do this way with repeatition
$j(document).ready(function() {
$j('#Button1').click( function () {
var data = $j("form").serialize();
$j.post('file.php', data, function(response){
$j("#Response").show();
});
});
$j('#Button21').click( function () {
var data = $j("form").serialize();
$j.post('file.php', data, function(response){
//do something else
});
});
});
I'd do it by adding a class to the selected buttons and then pull the event.target id from the click function:
$j('.buttons').click(function(e) {
var buttonId = e.target.id,
data = $j("form").serialize();
$j.post('file.php', data, function(response) {
switch (buttonId) {
case "Button1":
$j("#Response").show();
break;
case "Button21":
//do something else
break;
}
});
});
You need to abstract the data from the functionality.
sendClick('#Button1', function() {
$j('#Response').show();
});
sendClick('#Button21', function() {
// do something
});
sendClick function
function sendClick(selector, callback)
{
$j(selector).click( function () {
var data = $j("form").serialize();
$j.post('file.php', data, callback);
});
}
This way you can repeat the same functionality over and over by changing the selector and the callback. You could customise this even further by:
function sendClick(selector, options, callback)
{
// handle arguments
if(typeof options == 'function') {
callback = options;
options = {};
} else {
options = options || {};
}
$j.extend({
form: 'form',
file: 'file.php'
}, options);
// abstracted logic
$j(selector).click(function() {
var data = $j(options.form).serialize();
$j.post(options.file, data, callback);
});
}
then use like
sendClick('#select', {form: '#anotherForm'}, function() {
// do something
});
or
sendClick('#another', function(response) {
// something else
});
You can attach the event to both, and then, when you need to check which element triggered the event, use event.target.
$j(function() {
$j('#Button1, #Button2').click( function (event) {
var data = $j("form").serialize();
$j.post('file.php', data, function(response){
if ($(event.target).is('#Button1')) {
$j("#Response").show();
} else {
// Do something else
}
});
});
});
Here are two different ways:
You can combine the two handlers into one handler:
$j(document).ready(function () {
$j('#Button1, #Button21').click(function() {
var id = this.id;
var data = $j("form").serialize();
$j.post('file.php', data, function(response) {
if (id == 'Button1') {
// Show
} else {
// Do something else
}
});
});
});
Or write a special kind of handler:
$j.fn.clickAndPost = function (handler) {
this.click(function () {
var me = this;
var data = $j("form").serialize();
$j.post('file.php', data, function(response) {
handler.call(me);
});
});
});
...and attach two of them:
$j(document).ready(function () {
$j('#Button1').clickAndPost(function () {
// Show
});
$j('#Button21').clickAndPost(function () {
// Do something else
});
});
$j(function($) {
$('#Button1', '#Button21').click(function() {
var that = this,
data = $('form').serialize();
$.post('file.php', data, function(response) {
if ( that.id === 'Button1' ) {
$('#Response').show();
} else {
//do something else
}
});
});
});
$(document).ready(function() {
$('#Button1 #Button21').click(function() {
var that = this.attr("id");
data = $('form').serialize();
$.post('file.php', data, function(response) {
if ( that === 'Button1' ) {
$('#Response').show();
} else {
//do something else
}
});
});
});
Let me know if it's not working.