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

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.

Related

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

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.

UI5 Messagebox synchron

Hi i implemented a Messagebox in a for loop, but i know the messagebox works asynchron.
I want that the programm wait for every loop to the desicion of the user.
onBook: function(oEvent) {
var that = this;
for (var i = 0; i < Items.length; i++){
function message(innerArg) {
sap.m.MessageBox.confirm(
"Text", {
icon : sap.m.MessageBox.Icon.INFORMATION,
title : "Really",
actions : [ sap.m.MessageBox.Action.YES,
sap.m.MessageBox.Action.NO ],
onClose : function(oAction) {
if (oAction === sap.m.MessageBox.Action.NO) {
delete(i);
}else{
}
}
});
}
message(i);
}
that.do(oEvent);
The programm jumps in the "do" method before a user action is done
Edit:
for (var i = 0; i < Items.length; i++){
(function (innerArg) {
sap.m.MessageBox.confirm(
"Delete?", {
icon : sap.m.MessageBox.Icon.INFORMATION,
title : "Delete",
actions : [ sap.m.MessageBox.Action.YES,
sap.m.MessageBox.Action.NO ],
onClose : function(oAction) {
if (oAction === sap.m.MessageBox.Action.NO) {
delete(innerArg)
}}
});
})(i);
}
that.Save(oEvent);
When the box is open the entries are booked because the programm goes to the save method without wating of user action Whats wrong ?
Ah, the asynchronous-function-in-a-synchronous-loop anti-pattern ;-)
You can try using closures:
for (var i = 0; i < items; i++) {
// use self-executing function here
(function(innerArg) {
sap.m.MessageBox.confirm(
"Text", {
onClose: function(oAction) {
if (oAction === sap.m.MessageBox.Action.NO) {
// here I want to do something
console.log("Value: ", innerArg);
}
}
}
);
})(i);
}
EDIT: Update with Promises
Based on your updated question, I have provided a more-or-less sorta-kinda working example (it may not work flawless, but it should show the design pattern you should follow)
You wrap the message box responses into a Promise resolve, and store these into an array. You then feed that array to Promise.all() in order to proceed with your save functionality
processData: function() {
var promises = [],
self = this;
for (var i = 0; i < items; i++) {
promises.push(this.doMessageboxAction(i));
}
Promise.all(promises).then(function(aData) {
aData.forEach(function(oData) {
self.save(oData);
});
}).catch(function(err) {
console.log(err);
});
}
doMessageboxAction: function(item) {
return new Promise(function(resolve, reject) {
sap.m.MessageBox.confirm(
"Text", {
onClose: function(oAction) {
if (oAction === sap.m.MessageBox.Action.NO) {
//do something
//etc
resolve(item); // or some other variable
}
else {
//do something else
//etc
resolve(item); // or some other variable
}
}
}
);
});
}

Multiple functions in restify function to elasticsearch client

I'm building a REST API using node and restify that communicaties with an elasticsearch database. Now when I delete an object, I want this to do a kind of cascading delete to some other objects. I know this is not really what to use elasticsearch for but bear with me.
So here is my code:
function deleteHostname(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
var endpoints = [];
client.search({
index: 'test',
type: 'something',
body: {
from: 0, size: 100,
query: {
match: {
hostname: 'www.test.com'
}
}
}
}).then(function (error, resp) {
if(error) {
res.send(error);
}
endpoints = resp.hits.hits;
for (index = 0, len = endpoints.length; index < len; ++index) {
client.delete({
index: 'test',
type: 'something',
id: endpoints[index]._id
}, function (error, response) {
if(error) {
res.send(error);
}
});
}
res.send(endpoints);
return next();
});
}
So basically I just want to search for any objects with hostname www.test.com ( I just hard coded this to test it ). Then I want to delete all objects I found. It follows the error path and sends me this:
{
"took":1,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"failed":0
},
"hits":{
"total":1,
"max_score":2.098612,
"hits":[
{
"_index":"test",
"_type":"something",
"_id":"123456",
"_score":2.098612,
"_source":{
"duration":107182,
"date":"2016-05-04 00:54:43",
"isExceptional":true,
"hostname":"www.test.com",
"eta":613,
"hasWarnings":false,
"grade":"A+",
"ipAddress":"ipip",
"progress":100,
"delegation":2,
"statusMessage":"Ready"
}
}
]
}
}
So in my opinion this doesn't look like an error? So why am I getting it back as an error? If I remove:
if(error) {
res.send(error);
}
From my code, I won't get any response.
You need to change your code like this (see the changes denoted by -> to the left):
if(error) {
1-> return res.send(error);
}
endpoints = resp.hits.hits;
for (index = 0, len = endpoints.length; index < len; ++index) {
2-> (function(id){
client.delete({
index: 'test',
type: 'something',
3-> id: id
}, function (error, response) {
if(error) {
4-> next(error);
}
});
5-> })(endpoints[index._id]);
}
6-> //res.send(endpoints);
I'm now explaining each change:
If you don't return you'll send the error and then you'll continue with processing the hits
(3/5) Since client.delete is an asynchronous function, you need to call it in an anonymous function
In case of error you need to call next(error) not res.send
You cannot send the response at this point since your for loop might not be terminated yet. Instead of a for loop, you should use the excellent async library instead (see an example of using asynch.each below)
Async example:
var async = require('async');
...
if(error) {
return res.send(error);
}
endpoints = resp.hits.hits;
async.each(endpoints,
function(endpoint, callback) {
client.delete({
index: 'test',
type: 'something',
id: endpoint._id
}, callback);
},
// this is called when all deletes are done
function(err){
if (err) {
next(err);
} else {
res.send(endpoints);
next();
}
}
);
Another solution for you to achieve exactly what you want is to use the delete by query plugin. That feature allows you to do all the above in a single query.
If you are still on ES 1.x, delete-by-query is still part of the core and you can simply call the deleteByQuery function of the Javascript client.
If you are on ES 2.x, delete-by-query is now a plugin, so yo need to install it and then also require the deleteByQuery extension library for the Javascript client
function deleteHostname(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
client.deleteByQuery({
index: 'test',
type: 'something',
body: {
query: {
match: { hostname: 'www.test.com' }
}
}
}, function (error, response) {
if (error) {
next(error);
} else {
res.send(endpoints);
next();
}
});
}

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.