Return JSONP from NodeJS server with AngularJS - angularjs

Im trying to implement ngInfiniteScroll - Loading Remote Data on my app.
The Demo works fine & I was successfully getting the Reddit API, but cant get my list to work.
I am successfully hitting 200 server response & can see my data in the dev tool. These answers have been some help 1 & 2 but I'm still not fully sure on what to do.
EDIT (see angular factory edit):
This callback is now working and $http is going to success however I'm now getting Cannot read property 'length' of undefined
Angular Factory:
Reddit.prototype.nextPage = function() {
if (this.busy) return;
this.busy = true;
// Edit - I changed this var from
// var url = config_api.API_ENDPOINT_LOCAL + "list?after=" + this.after + "?alt=json-in-script&jsonp=JSON_CALLBACK";
// to
var url = config_api.API_ENDPOINT_LOCAL + "list?after=" + this.after + "?alt=json-in-script&callback=JSON_CALLBACK";
$http.jsonp(url)
.success(function(data) {
console.log(data);
var items = data.children;
for (var i = 0; i < items.length; i++) {
this.items.push(items[i].data);
}
this.after = "t3_" + this.items[this.items.length - 1].id;
this.busy = false;
}.bind(this));
console.log('Reddit.prototype');
};
NodeJS Route:
app.get('/list', function (req, res) {
Found.find(function (err, post) {
if ( err ) {
res.send( err );
}
res.jsonp( post );
});
});

Reddit.prototype.nextPage = function() {
if (this.busy) return;
this.busy = true;
// Edit - I changed this var from
// var url = config_api.API_ENDPOINT_LOCAL + "list?after=" + this.after + "?alt=json-in-script&jsonp=JSON_CALLBACK";
// to
var url = config_api.API_ENDPOINT_LOCAL + "list?after=" + this.after + "?alt=json-in-script&callback=JSON_CALLBACK";
$http.jsonp(url)
.success(function(data) {
console.log(data);
var items = data;
for (var i = 0; i < items.length; i++) {
this.items.push(items[i]);
}
this.after = "t3_" + this.items[this.items.length - 1].id;
this.busy = false;
}.bind(this));
console.log('Reddit.prototype');
};
Should fix it!

Related

Posting to Node.js post function from AngularJS

I am having problem posting to a function in my back-end (Node.js) from my front-end (AngularJS).
I keep getting a 404 error. Could someone see if there is something wrong with my code as I can't see what may be causing this.
Front end
MockUpMaker_v1/js/controller.js
// All photos've been pushed now sending it to back end
$timeout(function () {
$http.post('/MockUpMaker_v1/savePhotos', $scope.photosToPhp).then(function (success) {
$scope.generating = false;
$scope.generateBtn = 'Generate';
//creating mock up gallery
for (var x = 0; x < success.data.photos; x++) {
var file = '/MockUpMaker_v1/tmp/' + success.data.folder + "/out" + x + ".png";
$scope.gallery.push(file);
}
$scope.photosToPhp = [];
}, function (error) {
});
},
Back end
MockUpMaker_v1/server.js
app.post('/MockUpMaker_v1/savePhotos', function(req, res){
var folder = Math.random().toString(36).substr(2, 20);
var photos = req.body;
var counts = 0;
var callback = function(counts){
if(counts < photos.length){
saveBase64(photos[counts], folder, counts, callback);
}else{
// var counts = 0;
var response = {"folder": folder, "photos": photos.length};
res.send(response)
}
};
saveBase64(photos[counts], folder, counts, callback);
});
Full back-end
As requested
"use strict";
var express = require('express');
var bodyParser = require('body-parser');
var fs = require('fs');
var mkdirp = require('mkdirp');
var archiver = require('archiver');
var app = express();
var server = require('http').Server(app);
app.use(bodyParser.json({limit: '50mb'}));
app.use(express.static('/public'));
app.use(express.static('/js'));
app.use(express.static('/tmp'));
app.use(express.static('/img'));
app.use(express.static('/css'));
app.get('/', function(req, res){
res.sendFile(__dirname + 'views/form-mockup.html')
});
app.post('/MockUpMaker_v1/savePhotos', function(req, res){
var folder = Math.random().toString(36).substr(2, 20);
var photos = req.body;
var counts = 0;
var callback = function(counts){
if(counts < photos.length){
saveBase64(photos[counts], folder, counts, callback);
}else{
// var counts = 0;
var response = {"folder": folder, "photos": photos.length};
res.send(response)
}
};
saveBase64(photos[counts], folder, counts, callback);
});
app.post('MockUpMaker_v1/downloadZip', function(req, res){
var photos = req.body;
var out = photos[0];
var test = out.split('/');
var loc = test.pop();
var end = test.join('/');
console.log(end);
var outName = '/' + end + '/MockUp.zip';
var output = fs.createWriteStream(outName);
var archive = archiver('zip', {store: true });
var zip = function(photos, f){
for(var t = 0; t < photos.length; t++){
var file = 'mockUp' + t + '.jpg';
var from = '/' + photos[t];
archive.file( from, { name: file });
}
f();
};
output.on('close', function() {
var photos = req.body;
var out = photos[0];
var test = out.split('/');
var loc = test.pop();
var end = test.join('/');
res.send(end + '/MockUp.zip');
console.log('archiver has been finalized and the output file descriptor has closed.');
});
archive.on('error', function(err) {
throw err;
});
archive.pipe(output);
zip(photos, f);
function f(){
archive.finalize();
}
});
server.listen(3000, function(){
console.log('sm2.0 server running');
});
function saveBase64(photo, folder, counts, callback){
var result = photo.split(',')[1];
var path = 'tmp/' + folder;
var filename = path + "/out" + counts + ".png";
mkdirp( path, function() {
fs.writeFile(filename, result, 'base64', function(error){
if (error) {
console.log('error saving photo');
}else{
console.log('photo saved');
counts++;
callback(counts);
}
});
});
}
And console printout
[nodemon] restarting due to changes... [nodemon] restarting due to
changes... [nodemon] starting node server.js sm2.0 server running
Inspect error
POST http://localhost:63342/MockUpMaker_v1/savePhotos 404 (Not Found)
In your Angular App, write the whole URL as the first argument of the $http.post function.
E.g. http://localhost:3000/MockUpMaker_v1/savePhotos

After searching in database. In Angular grid, infinite scrolling is not working

After database search using filter, scrolling is not working otherwise it works fine. Below is my code for get data down method.
$scope.getDataDown = function() {
var promise = $q.defer();
$scope.lastPage++;
if ($scope.data.length < $scope.total) {
$http(getRequest()).success(function(data) {
promise.resolve();
$scope.gridApi.infiniteScroll.saveScrollPercentage();
$scope.data = $scope.data.concat(data.content);
$scope.total = data.total ? data.total : data.length;
$scope.length = $scope.data.length;
$scope.dataLength = $scope.data.length;
$scope.gridApi.infiniteScroll.dataLoaded(false,
$scope.lastPage < ($scope.total / $scope.pageSize));
}).error(function(error) {
$scope.gridApi.infiniteScroll.dataLoaded();
});
}
return promise.promise;
};

how to handle multiple delete and displaying 1 message using delete service in angular JS

When i check all lists in table, and press delete button, A DELETE SERVICE will be called.(Using AngularJS)
Problem is, i am using a loop, and on successful delete and unsuccessful delete, i am getting alert multiple times.(No. of selection times)
And its not working properly, if place it out of loop because its Async Task.
Here is the code,
This is a controller which initiates a service.
$scope.confirmAction = function() {
var costsToDelete = [];
angular.forEach($scope.objects, function(cost) {
if (cost.selected == true) {
costsToDelete.push(cost);
}
});
$scope.deleted = true;
//need to put confirmation dialog here.
//URL: specific to timesheet deletion. it will be prefixed with constant url
var delRequestUrl = URLs.costsUrl + '/';
deleteService.deleteRecord($scope.objects, costsToDelete, delRequestUrl);
};
This is a service.
.service('deleteService', ['dataService', 'Constant.urls', 'Constants','$q','alerts',function(dataService, URLs, Constants, $q, alerts) {
var deleteService = {};
deleteService.deleteRecord = function(records, listOfRecordsToDelete, url) {
while (listOfRecordsToDelete.length > 0) {
var recordToBeDeleted = listOfRecordsToDelete.pop();
var index = listOfRecordsToDelete.indexOf(recordToBeDeleted);
var delRequestUrl = url + recordToBeDeleted.id;
var result = dataService.deleteObject(delRequestUrl);
result.success(function(data) {
Alert('success');
records.splice(index, 1);
});
result.error(function(data, status, headers, config) {
dataService.handleError(status,data);
Alert('error');
});
}
};
return deleteService; }])
I need a result like: Alert should display only once.
If all items are successfully deleted, then success or failure message.
Why dont you just create a boolean bit var status= false;//default value to true inside success callback handler and false inside error callback handler,
so once all calls are complete based on this bit you can alert success or failure
Angular JS Code:
.service('deleteService', ['dataService', 'Constant.urls', 'Constants','$q','alerts',function(dataService, URLs, Constants, $q, alerts) {
var statusBit = false; // status tracker
var deleteService = {};
deleteService.deleteRecord = function(records, listOfRecordsToDelete, url) {
while (listOfRecordsToDelete.length > 0) {
var recordToBeDeleted = listOfRecordsToDelete.pop();
var index = listOfRecordsToDelete.indexOf(recordToBeDeleted);
var delRequestUrl = url + recordToBeDeleted.id;
var result = dataService.deleteObject(delRequestUrl);
result.success(function(data) {
// Alert('success');
statusBit = true;
records.splice(index, 1);
});
result.error(function(data, status, headers, config) {
dataService.handleError(status,data);
//Alert('error');
statusBit = false;
});
if(statusBit){
Alert('success'); //console.log('successfully deleted');
}
else {
Alert('error'); // console.log('error while deleting');
}
};
return deleteService; }])
.service('deleteService', ['dataService', 'Constant.urls', 'Constants','$q','alerts',function(dataService, URLs, Constants, $q, alerts) {
var deleteService = {};
deleteService.deleteRecord = function(records, listOfRecordsToDelete, url) {
var overallResult = true;
while (listOfRecordsToDelete.length > 0) {
var recordToBeDeleted = listOfRecordsToDelete.pop();
var index = listOfRecordsToDelete.indexOf(recordToBeDeleted);
var delRequestUrl = url + recordToBeDeleted.id;
var result = dataService.deleteObject(delRequestUrl);
result.success(function(data) {
records.splice(index, 1);
});
result.error(function(data, status, headers, config) {
dataService.handleError(status,data);
overallResult = false ;
});
}
};
return deleteService; }])

Foreach loop in AngularJS and $http.get

I have problem with my AngularJS function. Data from first forEach is retrieved with $http.get and in second forEach, $scope.products isn't defined yet. I know that $http.get() is an asynchronous request and this is the point... But how to rewrite this function to work fine ?
$scope.getAll = function () {
var cookies = $cookies.getAll();
$scope.products = [];
var i = 0;
angular.forEach(cookies, function (v, k) {
console.log("important1:" + $scope.products);
console.log("key: " + k + ", value: " + v);
ProductsService.retrieve(k).then(function(response) {
$scope.products = $scope.products.concat(response.data);
$scope.products[i].quantity = v;
i++;
}, function (error) {
console.log('error');
});
});
console.log("important2:" + $scope.products);
angular.forEach($scope.products, function(value, key) {
$scope.total = value.quantity*value.price + $scope.total;
console.log("Quantiy: " + value.quantity);
console.log("Price: " + value.price);
});
console.log($scope.products);
console.log($scope.total);
};
I suggest that you use the $q.all().
More specifically, you would do:
$q.all([p1, p2, p3...]).then(function() {
// your code to be executed after all the promises have competed.
})
where p1, p2, ... are the promises corresponding to each of your ProductsService.retrieve(k).
Build up a list of service calls then call $q.all. Inside the then function you can put your second loop.
var listOfServiceCalls = [];
//Add to list of service calls
$q.all(listOfServiceCalls)
.then(function () {
//All calls completed THEN
angular.forEach($scope.products, function(value, key) {
$scope.total = value.quantity*value.price + $scope.total;
});
});

AngularJS paging

I made AngularJS pagination with spring mvc It works well ,but the application get a large amount of data from database so the application is very slow when I get first page because it get all records,Can anyone help me to solve this problem?I want to get subset of data from database depending on angularJS pagination
Spring mvc Controlller
#RequestMapping(value = "/rest/contacts",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public List<Contact> getAll() {
return contactRepository.findAll();
}
AngularJS Service
pagingpocApp.factory('Contact', function ($resource) {
return $resource('app/rest/contacts/:id', {}, {
'query': { method: 'GET', isArray: true},
'get': { method: 'GET'}
});
});
AngularJS Controller
pagingpocApp.controller('ContactController', function ($scope, $filter,resolvedContact, Contact, resolvedRole) {
$scope.contacts = resolvedContact;
var sortingOrder = 'firstName';
$scope.sortingOrder = sortingOrder;
$scope.reverse = false;
$scope.filteredItems = [];
$scope.groupedItems = [];
$scope.itemsPerPage = 10;
$scope.pagedItems = [];
$scope.currentPage = 0;
var searchMatch = function (haystack, needle) {
if (!needle) {
return true;
}
return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1;
};
// init the filtered items
$scope.search = function () {
$scope.filteredItems = $filter('filter')($scope.contacts, function (item) {
for(var attr in item) {
if (searchMatch(item[attr], $scope.query))
return true;
}
return false;
});
// take care of the sorting order
if ($scope.sortingOrder !== '') {
$scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse);
}
$scope.currentPage = 0;
// now group by pages
$scope.groupToPages();
};
// calculate page in place
$scope.groupToPages = function () {
$scope.pagedItems = [];
for (var i = 0; i < $scope.filteredItems.length; i++) {
if (i % $scope.itemsPerPage === 0) {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [ $scope.filteredItems[i] ];
} else {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]);
}
}
};
$scope.range = function (start, end) {
var ret = [];
if (!end) {
end = start;
start = 0;
}
for (var i = start; i < end; i++) {
ret.push(i);
}
return ret;
};
$scope.prevPage = function () {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.nextPage = function () {
if ($scope.currentPage < $scope.pagedItems.length - 1) {
$scope.currentPage++;
}
};
$scope.setPage = function () {
$scope.currentPage = this.n;
};
// functions have been describe process the data for display
$scope.search();
// change sorting order
$scope.sort_by = function(newSortingOrder) {
if ($scope.sortingOrder == newSortingOrder)
$scope.reverse = !$scope.reverse;
$scope.sortingOrder = newSortingOrder;
// icon setup
$('th i').each(function(){
// icon reset
$(this).removeClass().addClass('icon-sort');
});
if ($scope.reverse)
$('th.'+new_sorting_order+' i').removeClass().addClass('icon-chevron-up');
else
$('th.'+new_sorting_order+' i').removeClass().addClass('icon-chevron-down');
};
});
One quick option would be to create a get method on your API that only returns a subset of the data, maybe only 25 contacts at a time, or a page or two worth of data. Then you could create a service in angular that makes that get call every 3 seconds or so to get the next 25 contacts. A sort of lazy loading technique.
Ben Nadel does a great job in this article of outlining how his company handles large sets of images being loaded to a page using a lazy loading technique. Reading through his example could give you a nice starting point.
Edit: I'm also going to recommend you refer to this solution for an answer slightly more on point to what you're looking to achieve. He recommends pushing data to your controller as soon as it's found:
function MyCtrl($scope, $timeout, $q) {
var fetchOne = function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve([random(), random() + 100, random() + 200]);
}, random() * 5000);
return deferred.promise;
};
$scope.scans = [];
for (var i = 0; i < 2; i++) {
fetchOne().then(function(items) {
angular.forEach(items, function(item) {
$scope.scans.push(item);
});
});
};
}

Resources