On app launch it checks if a certain file exists, if not then it will make an http request to get an API in json format. If the request is successfully done, then it will create a json file.
The $cordova.writeFile() logs in success handler so it must have worked (I don't know how to check if it indeed made one though).
When I close the app and relaunch it then it checks again but it goes always in the error handler doesn't exist
// On launch
$scope.checkFile('news.json');
$scope.checkFile = function(file){
$cordovaFile.checkFile(cordova.file.dataDirectory, file)
.then(function (success) {
console.log('Exists!');
}, function (error) {
console.log('Doesnt exist');
$scope.update();
});
}
//If it doesn't exist
$scope.update = function () {
// Get all news
NewsService.getAllNews().then(function (data) {
$scope.saveFile('news.json', data);
$scope.news = data;
}, function (err) {
console.log(err)
});
};
// Write file
$scope.saveFile = function (file, data) {
console.log(file) // logs news.json
console.log(data) // logs data
$cordovaFile.writeFile(cordova.file.dataDirectory, file, JSON.stringify(data), true)
.then(function (success) {
// success
console.log('Worked!');
}, function (error) {
// error
console.log('Didn't work');
});
};
Edit:
cordova.file.dataDirectory leads to:
file:///data/user/0/com.myname.appname/files/
Is this the correct path?
Edit2:
Instead of logging my own error, I logged the variable error. It says:
FileError {code: 5, message: "ENCODING_ERR"}
Related
I have a submit function, which posts some data into a server and then the server returns a response. The function is working fine. I would like, though, to catch a couple of errors during the post process. For example, if there is no connectivity to the server, return an error to the user to inform him what's going on. instead of just pressing the button and do nothing. I know I can create a function to somehow ping the server and check if it's alive but that's not what I need. I would like to have a statement in the error function and catch most of the possible errors and output an explanation to the user.
$scope.submit = function() {
var link = 'http://app.example.com/api.php';
$http.post(link, {
username: $scope.data.username,
password: $scope.data.password
}).then(function(res) {
$scope.response = res.data;
$localStorage.token = res.data;
console.log($localStorage.token);
})
.catch(function(error) {
console.error(error);
})
.finally(function() {
//do something
});
};
Solution:
$http.post(link, {
username: md5.createHash($scope.data.username),
password: md5.createHash($scope.data.password),
}).then(function(res) {
//Success Scenario
})
.catch(function(error) {
if (error.statusText == ""){
$scope.response = "Unexpected error. Make sure WiFi is on."
//When the device is not connected on the internet the response error is -1 (or any number) and the statusText is empty. So we caching that one as-well.
}
else {
$scope.response = "Error - "+error.status + " ("+error.statusText+")";
//else we display the error along with the status, for example error 500 Internal Server error.
}
})
.finally(function() {
//This function will always be called at the end. Take advantage of it :)
});
I hope it's gonna be useful for someone.
I'm actually working on a webclient calling a REST service.
After my last question, the GET request is working now.
Now i want o implement a DEL request using angulars delete method.
In the following example is my service request implemented.
function ItemsService($http) {
this.$http = $http;
}
ItemsService.prototype = {
deleteFoo: function (id) {
this.$http.delete('http://localhost:3001/posts/' + id)
.then(function successCallback(response) {
console.log("DEL send...");
console.log(response.data);
}, function errorCallback(response) {
console.log('Error');
});
}
}
module.exports = {
ItemsService: ItemsService
}
I added a button on the webpage with ng-click="$ctrl.deleteMe()".
The controller looks like the following example:
function Foo(ItemsService) {
this.itemsService = ItemsService;
}
Foo.prototype = {
deleteMe: function () {
console.log('delete now');
this.itemsService.deleteFoo(1).then(
response => {
console.log('gelöscht? ' + response);
}
);
}
};
If i now click on the button, nothing happens. In the network trace log in the dev tools in the browser i can't see a DEL request.
To test this REST service request, i run the JSON Server tool on port 3001.
I testet the availability of the server with SOAPUI, it works, i see all the requests in the console.
But no request from my test webpage.
Can anyone help me?
You need to return
return this.$http.delete('http://localhost:3001/posts/' + id)
.then(function successCallback(response) {
console.log("DEL send...");
console.log(response.data);
}, function errorCallback(response) {
console.log('Error');
});
I have a requirement which requires chaining of Promises. In my Ionic app, I need to iterate over a list of files and zip them. Then the zip needs to be stored on the device itself (iPhone in this case).
I already have the list of files that need to be zipped in an array. So, I am iterating over them and using $cordovaFile getting the binay content of these files. Then I am adding binary to a JSZip object. End result should be that binary content of all the files should be added to zip.file, so that a zip file can be generated.
//wrapping in Promise.all so that we don't proceed until we have the content of all files added to zip
var zip = new JSZip();
return Promise.all(
filesList.forEach(function(file) {
console.log('file to be added using $cordovaFile '+file);
// Getting the content of each file using $cordovaFile. This returns a promise.
return $cordovaFile.readAsBinaryString(cordova.file.dataDirectory + $rootScope.username, file)
.then(function(binaryData) {
return new Promise(function(resolve, reject) {
//Adding content of all files to zip.file so that it can be zipped in the next step.
resolve(zip.file(file, binaryData, {binary: true}));
})
})
.catch(function(error) {
console.log('Error during fetch content or zipping '+JSON.stringify(error));
})
})
)
Once zip.file has all the contents, I am calling another function in JSZip which would generate the zip. This would return a promise as well, so I need to chain to $cordovaFile.writeFile, so that the zip can be written locally. $cordovaFile.writeFile also returns a Promise which would the last promise in the chain.
.then(function(zipData) {
// async request to generate the zip
return zipData.generateAsync({type:"blob"});
}).then(function (blob) {
// once we have the zip, save it to the device
$cordovaFile.writeFile(cordova.file.dataDirectory+$rootScope.username, 'abc.zip', blob, true)
.then(function(data) {
console.log('Zip file written to device at '+cordova.file.dataDirectory+$rootScope.username);
})
}).catch(function(error) {
console.log('Error while zipping and writing '+JSON.stringify(error));
})
This is how the complete code looks like
var zipFiles = function(filesList) {
var zip = new JSZip();
return Promise.all(
filesList.forEach(function(file) {
return $cordovaFile.readAsBinaryString(cordova.file.dataDirectory + $rootScope.username, file)
.then(function(binaryData) {
return new Promise(function(resolve, reject) {
resolve(zip.file(file, binaryData, {binary: true}));
})
})
.catch(function(error) {
console.log('Error during fetch content or zipping '+JSON.stringify(error));
})
})
)
.then(function(zipData) {
return zipData.generateAsync({type:"blob"});
}).then(function (blob) {
$cordovaFile.writeFile(cordova.file.dataDirectory+$rootScope.username, 'abc.zip', blob, true)
.then(function(data) {
console.log('Zip file written to device at '+cordova.file.dataDirectory+$rootScope.username);
})
}).catch(function(error) {
console.log('Error while zipping and writing '+JSON.stringify(error));
})
}
Challenge is that after Promise.all completes, nothing gets executed. So, nothing starting 'then(function(zipData)' gets executed.
I feel it has something to do with the way I am chaining Promises. Any help will be highly appreciated.
This is because forEach returns undefined, thus Promise.all resolves immediately. You should change that to .map.
Moreover, keep in mind that your zipData argument would not be what you expect. This promise's arguments will contain every result returned from zip.file(file, binaryData, {binary: true}).
In this case you do not need the zipData. The zip variable will do the job. In the code bellow I have also simplified the promises chain by removing a redundant promise in the loop and taking one .then outside.
var zipFiles = function (filesList) {
var zip = new JSZip();
var zipFilesPromises = filesList.map(function (file) {
return $cordovaFile.readAsBinaryString(cordova.file.dataDirectory + $rootScope.username, file)
.then(function (binaryData) {
return zip.file(file, binaryData, { binary: true });
});
});
return Promise.all(zipFilesPromises)
.then(function () {
return zip.generateAsync({ type: "blob" });
})
.then(function (blob) {
return $cordovaFile.writeFile(cordova.file.dataDirectory + $rootScope.username, 'abc.zip', blob, true);
})
.then(function (data) {
console.log('Zip file written to device at ' + cordova.file.dataDirectory + $rootScope.username);
})
.catch(function (error) {
console.log('Error while zipping and writing ' + JSON.stringify(error));
})
}
The reason Promise.all never resolves is that filesList.forEach never returns any values.
I think modifying to fileList.map will solve your issue.
So change your code as follows:
var zipFiles = function(filesList) {
var zip = new JSZip();
return Promise.all(
filesList.map(function(file) {
return $cordovaFile.readAsBinaryString(cordova.file.dataDirectory + $rootScope.username, file)
.then(function(binaryData) {
return new Promise(function(resolve, reject) {
resolve(zip.file(file, binaryData, {binary: true}));
})
})
.catch(function(error) {
console.log('Error during fetch content or zipping '+JSON.stringify(error));
})
})
)
.then(function(zipData) {
return zipData.generateAsync({type:"blob"});
}).then(function (blob) {
$cordovaFile.writeFile(cordova.file.dataDirectory+$rootScope.username, 'abc.zip', blob, true)
.then(function(data) {
console.log('Zip file written to device at '+cordova.file.dataDirectory+$rootScope.username);
})
}).catch(function(error) {
console.log('Error while zipping and writing '+JSON.stringify(error));
})
}
For put request:
router.put('/:id', controller.update);
My update method look like this:
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Thing.findById(req.params.id, function (err, thing) {
if (err) { return handleError(res, err); }
if(!thing) { return res.status(404).send('Not Found'); }
var updated = _.merge(thing, req.body);
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.status(200).json(thing);
});
});
};
Making request:
$http.put('/api/things/'+ thing._id, updatedThingObject)
.success(function(update){
console.log("update", update)
})
.error(function(err){
console.log("err", err)
})
It gives connection error on passing the object while making the request in angular.
The error looks like this:
PUT http://localhost:9000/api/things/56c8325b9a0ee7d00d266495
net::ERR_CONNECTION_REFUSED(anonymous function) # angular.js:11442sendReq #
If I take off the updated object, it makes the request just fine but ofcourse nothing gets updated in
that case. What might be wrong here,please?
I figured.
The reason for the functions not being called is that I have a function that is being called repetitively in Node .
var autoCreate = function(){
console.log("THING CREATED AUTOMATICALLY")
var randomNumb=0;
clearTimeout(randomNumb);
randomNumb = (Math.random()* (10-5) + 5).toFixed(0);
console.log("random number", randomNumb)
var randomThing =randomstring({
length: randomNumb,
numeric: false,
letters: true,
special: false
});
console.log("ranfom thing", randomThing)
Thing.create({
name: randomThing,
readByUser: false
}, function(err, thing) {
console.log("THING IS", thing)
//setTimeout(autoCreate, randomNumb * 1000);
});
}
setTimeout(autoCreate, 10*1000);
Since this is running when post/put request is made, I get connection error. How do I handle this to be able to have this function running and be able to make put/post requests as well?
My back-end call is returning undefined. A.k.a TypeError: Cannot read property 'then' of undefined. I think I am calling it incorrectly.
Here is the AngularJS controller code:
$scope.addUser = function (chaseUser) {
Accounts.addChaseUser(userToSubmit).then(function (response, err) {
if (err) {
$scope.errorMessage = "There was an error.";
$log.debug(err);
} else if (response) {
$scope.errorMessage = "It worked.";
$log.debug(response);
} else {
$scope.errorMessage = "No 'response' nor 'err' returned from backend";
}
});
};
How this responds is that if...
(1) I put in correct credentials, I get a response that comes back with all the transaction data but still TypeError: Cannot read property 'then' of undefined in the console.
(2) Input incorrect credentials, I get no error object, response object, or even making it down to the line where I have $scope.errorMessage = "No 'response' nor 'err' returned from backend"; plus, of course, `cannot read property 'then' of undefined.
Corresponding AngularJS service:
return {
addChaseUser: function(credentials) {
return Restangular.one('user').customPOST(credentials, 'addUser');
}
};
On the backend (controller):
module.exports = {
addChaseUser: function (req, res) {
PlaidService.provideCredentialsToMFA(req.body, function (err, mfaRes) {
if (err) {
return res.status(403).json(err);
}
return res.json(mfaRes);
});
},
};
Backend service:
var plaid = require('plaid');
var plaidClient = new plaid.Client('test_id', 'test_secret', plaid.environments.tartan);
module.exports = {
provideCredentialsToMFA: function (credentials, cb) {
Q.fcall(PlaidService.connectUser.bind(this, credentials))
.then(PlaidService.saveUsersAccessToken.bind(this, credentials))
.then(PlaidService.getTransactionData.bind(this, credentials))
.then(function(transactions) {
cb(null, transactions);
},
function(err) {
console.log(err);
cb(err, null);
});
},
}
How am I supposed to be calling this Restangular POST from the AngularJS controller? It should not be returning undefined.
Since you are getting the response from the server side, it means that your server side code and the angular service code is working just fine. :)
The only possibility I can see is that I is wrong with the application of .then() block is that insted of two parameters(i.e., response and err) lets try with only one parameter.
Something like following :
$scope.addUser = function (chaseUser) {
Accounts.addChaseUser(userToSubmit).then(function (response) {
if(response.status == 'error'){
$log.debug('Got error in the response');
}else{
$log.debug('SUCCESS');
}
});
};
I have used .then(function(data)) with only one parameter. That is the only thing I could find :)
Incase you still don't see it, you are missing a few returns in your functions.
addUser: function (req, res) {
return PlaidService.provideCredentialsToMFA(
// ... your code ...
);
},
provideCredentialsToMFA should return the promise
provideCredentialsToMFA: function (credentials, cb) {
return plaidClient.addConnectUser(
// ... Your code ...
);
}
EDIT:
simplifying the working code looks something like this. Notice there are no returns and only callbacks are used:
findChargeById: function (req, res) {
fetchCharge(someParams, someCallBack);
}
fetchCharge: function (chargeId, cb) {
stripe.charges.retrieve(chargeId, anotherCallBack);
}
Your code looks like this. It's similar but the $scope.addUser expects something returned and doesn't use a callback
addUser: function (req, res) {
provideCredentialsToMFA(someParams, someCallBack);
// addUser returns nothing
}
provideCredentialsToMFA: function (credentials, cb) {
plaidClient.addConnectUser(someParams, someCallBack);
// provideCredentialsToMFA returns nothing and it seems plaidClient.addConnectUser returns nothing too
}
$scope.addUser = function (userInfo) {
// Here is the difference with your 'then' call. Accounts.addUser doesn't return anything and takes 2 params
Accounts.addUser(userInfo).then(someCallBack);
};