My service parsing RSS with googleapis and returns a array's Object containing others Objects.
Below, the chrome console ouput :
[Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
0: Object
1: Object
2: Object
3: Object
But in my controller cannot use localStorage to retrieve data, the console output return only bracket or nothing :
$scope.feeds = FeedList.get();
window.localStorage.setItem('savedData', JSON.stringify($scope.feeds));
console.log('TEST : ' + window.localStorage['savedData']);
console.log('TEST : ' + JSON.parse(window.localStorage.getItem('savedData')));
console.log('TEST : ' + JSON.parse(window.localStorage['savedData']));
Ouput :
TEST : []
TEST :
TEST :
Please, what is wrong ?
service.js
.factory('FeedLoader', function ($resource) {
return $resource('http://ajax.googleapis.com/ajax/services/feed/load', {}, {
fetch: { method: 'JSONP', params: {v: '1.0', callback: 'JSON_CALLBACK'} }
});
})
.service('FeedList', function ($rootScope, FeedLoader) {
var feeds = [];
this.get = function() {
var feedSources = [
{title: 'rss1', url: 'http://www.website.com/rss/feed/rss_feed_25300'},
{title: 'rss2', url: 'http://www.website.com/rss/feed/rss_feed_10720'},
];
if (feeds.length === 0) {
for (var i=0; i<feedSources.length; i++) {
FeedLoader.fetch({q: feedSources[i].url, num: 10}, {}, function (data) {
var feed = data.responseData.feed;
console.log(feed.entries);
feeds.push(feed.entries);
});
}
}
return feeds;
};
})
What's wrong is that FeedList.get() uses asynchrony and $scope.feeds will not be populated right away.
Try this:
$scope.feeds = FeedList.get();
$scope.feeds.then(function () {
// $scope.feeds is done loading now
window.localStorage.setItem('savedData', JSON.stringify($scope.feeds));
console.log('TEST : ' + window.localStorage['savedData']);
console.log('TEST : ' + JSON.parse(window.localStorage.getItem('savedData')));
console.log('TEST : ' + JSON.parse(window.localStorage['savedData']));
});
Edit: Now that you've provided the code for your service, it's clear that it doesn't return a promise. You need to do that in order for the consumers of your service to be able to wait on the results:
.service('FeedList', function ($rootScope, $q, FeedLoader) {
var feeds;
this.get = function() {
var feedSources = [
{title: 'rss1', url: 'http://www.website.com/rss/feed/rss_feed_25300'},
{title: 'rss2', url: 'http://www.website.com/rss/feed/rss_feed_10720'},
];
if (!feeds) {
var feedPromises = feedSources.map(function (source) {
return FeedLoader.fetch({q: source.url, num: 10}, {}).$promise
.then(function (data) {
return data.responseData.feed.entries;
});
});
feeds = $q.all(feedPromises)
.then(function (retrievedFeeds) {
return Array.prototype.concat([], retrievedFeeds);
});
}
return feeds;
};
})
The problem is that you don't handle async request properly, so:
$scope.feeds = [];
console.log('TEST : Load feeds async');
FeedList.get().then(function () { // each feed comes as argument
angular.forEach(arguments, function (feed) {
$scope.feeds.concat(feed); // merge arrays
});
window.localStorage.setItem('savedData', JSON.stringify($scope.feeds));
console.log('TEST : ' + window.localStorage['savedData']);
console.log('TEST : ' + JSON.parse(window.localStorage.getItem('savedData')));
console.log('TEST : ' + JSON.parse(window.localStorage['savedData']));
});
Service:
.service('FeedList', function ($q, $rootScope, FeedLoader) {
this.get = function () {
var promises = []; // to handle async loading
var feedSources = [{
title: 'rss1',
url: 'http://www.website.com/rss/feed/rss_feed_25300'
}, {
title: 'rss2',
url: 'http://www.website.com/rss/feed/rss_feed_10720'
}];
angular.forEach(feedSources, function (source) {
var defer = $q.defer();
FeedLoader.fetch({
q: source.url,
num: 10
}, {}, function (data) {
var feed = data.responseData.feed;
defer.resolve(feed.entries); // todo - need to handle errors with 'defer.reject'
});
promises.push(defer.promise);
});
return $q.all(promises);
};
})
Related
I would like to use Angular 1.6.5 for a project rebuild, but I'm not sure how to use the $http.get request in a factory when the source returns only a limited number of records at a time (1000 returned per request) and there are over 2000 records that I need to get.
In my current code I use jquery ajax and in the .done method I check for the presence of the value "__next", and if it exists, I recall the function passing the value "__next". When the "__next" value isn't returned, I do something with the data.
function getSpecifiedList(url){
var specUrl = url;
$.ajax({
url: specUrl,
type: "GET",
headers:{"accept":"application/json;odata=verbose",
error: function(xhr){
console.log(xhr.status + " " + xhr.statusText);
}
}
}).done(function (results){
$("#wc_report_holder").text(results.length);
//buildObjects processes the results and adds to an array
buildObject(results);
if(results.d.__next){
getSpecifiedList(results.d.__next);
}else{
buildGridView();
}
}).fail(function(error){
$("#wc_report_holder").text("There was an error: " + error);
});
}
I would like to figure out how to implement that same value check and recursive call in angular 1.6.5 using best practice and most efficient but I haven't had luck figuring it out based on the angular docs and Googling.
Here is a short version of what I currently have using Angular 1.6.5.
<script>
var sitesApp = angular.module("sitesApp", ['ngRoute']);
sitesApp.controller('SitesListCtrl', ['$scope', 'sites',
function ($scope, sites) {
sites.list().then(function (response) {
$scope.sites = response.data.value;
});
}
]);
sitesApp.controller("SiteDetailsCtrl", ['$scope', '$routeParams', 'sites',
function ($scope, $routeParams, sites) {
sites.find($routeParams.SiteCodePc, function (site) {
$scope.site = site;
});
}
]);
sitesApp.config(function ($routeProvider, $locationProvider) {
$locationProvider.hashPrefix('!');
$routeProvider.
when('/', {
templateUrl: 'https://machine/sites/site-list.html',
controller: 'SitesListCtrl'
}).
when('/:SiteCodePc', {
templateUrl: 'https://machine/sites/site-details.html',
controller: 'SiteDetailsCtrl'
}).
otherwise({
redirectTo: '/'
});
});
sitesApp.factory('sites', ['$http', function ($http) {
var urlBase = "https://some-endpoint-for-data";
var cachedData;
function getData(callback) {
if (cachedData) {
callback(cachedData);
} else {
return $http({
method: 'GET',
url: urlBase
})
.then(function (response) {
//HERE IS WHERE I THINK THE SOLUTION NEEDS TO BE IMPLEMENTED
cachedData = response;
return cachedData;
});
}
}
return {
list: getData,
find: function (SiteCodePc, callback) {
getData(function (response) {
var site = response.data.value.filter(function (entry) {
//debugger;
return entry.SiteCodePc === SiteCodePc;
});
callback(site[0]);
});
}
};
}]);
</script>
<div ng-app="sitesApp">
<div ng-view></div>
</div>
Thanks in advance
It looks like you can do a simple recursion where you accept a second (optional) parameter. If you are calling getData() for the first time then you can get your first 1000 results. However if you find __next then you will call it again sending the current 1000 results you have and concat the next 1000 results with the previous 1000.
sitesApp.factory('sites', ['$http', function ($http) {
var urlBase = "https://some-endpoint-for-data";
function getData(callback, results) {
return $http({
method: 'GET',
url: urlBase
})
.then(function (response) {
// If you have found a previous batch of results then concat the two arrays
if(results) {
response = response.concat(results);
}
// If there are more results to be found then recursively call the same function passing the batched results
if(response.__next) {
return getData(callback, response);
}
// If there are no more results to be found then trigger your callback function
else {
callback(response);
}
});
}
return {
list: getData,
find: function (SiteCodePc, callback) {
getData(function (response) {
var site = response.data.value.filter(function (entry) {
//debugger;
return entry.SiteCodePc === SiteCodePc;
});
callback(site[0]);
});
}
};
}]);
I have implemented same kind of scenario with pagination logic and $q. In this sample code I am pulling the records recursively as lazy based on the LazyloadingLimit. You can specify the limit based on your requirement.So it only pulls the records based on the count from the total collection. In this below sample I am not using $http. On your real sample you can use the $http to pull the records from the server. Here I just hard coded the collection initially.
In your case you have to fetch total records count initially and apply some pagination logic or some other parameter to pull the next records.
angular.module('app', []);
angular.module('app').controller('SampleController', function ($scope,$http, $timeout, $q) {
// $scope.initialize();
$scope.mainCount = 0;
$scope.lazyloadingLimit = 2;
$scope.tileDefinitions = null;
$scope.tempList = null;
$scope.totalRecordCollection = [
{ "Name": "Record1" },
{ "Name": "Record2" },
{ "Name": "Record3" },
{ "Name": "Record4" },
{ "Name": "Record5" },
{ "Name": "Record6" },
{ "Name": "Record7" },
];
function getTotalRecordCollection() {
var deferred = $q.defer();
deferred.resolve($scope.totalRecordCollection);
return deferred.promise;
}
$scope.initialize = function () {
debugger;
var currentCount=0;
var pageList = new Array();
var currentPage = 1;
var numberPerPage = 2;
var numberOfPages = 0;
function makeList() {
numberOfPages = getNumberOfPages();
}
function getNumberOfPages() {
return Math.ceil($scope.tempList.length / numberPerPage);
}
function nextPage() {
currentPage += 1;
}
function loadList() {
var deferred = $q.defer();
if (currentCount !== $scope.tempList.length) {
var begin = ((currentPage - 1) * numberPerPage);
var end = begin + numberPerPage;
pageList = $scope.tempList.slice(begin, end);
currentCount = currentCount + pageList.length;
$scope.mainCount = currentCount;
deferred.resolve(true);
} else {
debugger;
return $q.reject();
}
return deferred.promise;
}
function loadNextRecords() {
loadList().then(function (res) {
nextPage();
loadNextRecords();
});
}
getTotalRecordCollection().then(function (response) {
debugger;
$scope.tempList = response;
makeList();
loadNextRecords();
});
}
});
<body ng-controller="SampleController">
<input type="button" value="Click Here" ng-click="initialize()"/>
{{mainCount}}
</body>
Once all the records are loaded , you should reject the promise else the recursive loops never end.
Hope this helps
I get some data through Myservice from another Controller. I can see {{users.data}} from the view, but users.length = 0 ,and $data is empty, that means I can't access to the content of MyService in getData function.. if i replace MyService with json data like
$scope.users=[{..},{..}] it works fine
thank you ..
app.service('MyService', function() {
return data = [];
});
app.controller('tableController', function ($scope,
$filter,NgTableParams,MyService) {
$scope.users= MyService
$scope.usersTable = new NgTableParams({
page: 1,
count: 6
}, {
getData: function(params) {
params.total($scope.users.length);
$scope.da = params.sorting() ? $filter('orderBy')
($scope.users, params.orderBy()) : $scope.da;
$scope.da= params.filter() ? $filter('filter')
($scope.da, params.filter()) : $scope.users;
return $scope.da.slice((params.page() - 1) *
params.count(), params.page() * params.count());
}
}
);
});
When you get your data in the first controller you call MyService.setData(data); The service will store in its local var data and keep it there. Then in the second controller you can retrieve that data by calling MyService.getData()
app.service('MyService', function() {
var ret = {
data: [],
setData: function(inData) {
ret.data = inData;
},
getData: function() {
return ret.data;
}
};
return ret;
});
the first controller 1
app.controller('EventCtrl', ['$scope', 'EventService', 'MyService',
function ($scope, EventService , MyService) {
var baseUrl = '';
$scope.getEvents=function()
{
var apiRoute = 'http://localhost:9811/notification/notification/';
var _Event = EventService.getAll(apiRoute);
_Event.then(function (response) {
$scope.events= response.data;
MyService.data = $scope.events;
MyService.setData($scope.events);
$scope.VarCtrl1= MyService;
},
function (error) {
console.log("Error: " + error);
});
}
$scope.getEvents()
}]);
i updated the service but it doesnt work ..so i modified the first controller like this what do you think?
app.controller('EventCtrl', ['$scope', 'EventService', 'MyService',
function ($scope, EventService , MyService) {
var baseUrl = '';
$scope.getEvents=function()
{
var apiRoute =
'http://localhost:9811/notification/notification/';
var _Event = EventService.getAll(apiRoute);
_Event.then(function (response) {
var data = response.data
MyService.setData(data);
$scope.VarCtrl1= MyService;
},
function (error) {
console.log("Error: " + error);
});
}
$scope.getEvents()
}]);
Thanks for the update of the service now its better ...i can have data in $users and $data in tableController but orderBy need an array but i get this :( when i do consoleLoge($scope.users)
Object {data: Array(0), setData: function, getData: function}data:
Array(9)0: Object1: Object2: Object3: Object4: Object5: Object6:
Object7: Object8: Objectlength: 9__proto__: Array(0)getData:
function ()setData: function (inData)proto: Object
tableController.js:24
I tried components methods in vue js. My code like this.
const Thread = Vue.component('threadpage', function(resolve) {
$.get('templates/thread.html').done(function(template) {
resolve({
template: template,
data: function() {
return {
data: {
title: "Data Table",
count: this.GetData
}
};
},
methods: {
GetData: function() {
var data = {
username : "newshubid",
data : {
page : 0,
length : 10,
schedule : "desc"
}
};
var args = {"data" : JSON.stringify(data)};
var params = $.param(args);
var url = "http://example-url";
var result;
DoXhr(url, params, function(response){
result = JSON.parse(response).data;
console.log("load 1", result);
});
setTimeout(function () {
console.log("load 2", result);
return result;
}, 1000);
}
},
created: function(){
this.GetData();
}
});
});
});
But, when I trying to use {{ data.count }} in template. Not showing result what i want. Even I tried return result in GetData.
Whats my problem ? And how to access data from methods ? Please help me, i'm a beginner. Thanks
See the edited code and comments I added below.
You tried to return the result by using return in the function from setTimeout, which won't help you return value from GetData.
Instead, You can just set the value in the callback function of your ajax request.
const Thread = Vue.component('threadpage', function(resolve) {
$.get('templates/thread.html').done(function(template) {
resolve({
template: template,
data: function() {
return {
data: {
title: "Data Table",
// NOTE just set an init value to count, it will be refreshed when the function in "created" invoked.
count: /* this.GetData */ {}
}
};
},
methods: {
GetData: function() {
var data = {
username : "newshubid",
data : {
page : 0,
length : 10,
schedule : "desc"
}
};
var args = {"data" : JSON.stringify(data)};
var params = $.param(args);
var url = "http://example-url";
var result;
var vm = this;
DoXhr(url, params, function(response){
result = JSON.parse(response).data;
// NOTE set data.count to responsed result in callback function directly.
vm.data.count = result;
});
// NOTE I think you don't need code below anymore.
// setTimeout(function () {
// console.log("load 2", result);
// return result;
// }, 1000);
}
},
created: function(){
this.GetData();
}
});
});
});
I'm attempting to pull images from the Google Feed API to display in an RSS reader I'm building. I've successfully pulled the publishedDate and contentSnippet, but cannot seem to get the image src. Below is my current feeds partial and controller. Here I'm simply trying to test out an approach by pulling the first image, but it's not returning anything.
feeds.html:
<div ng-repeat="feed in feeds | orderBy:'title'">
<span ng-repeat="item in feed.entries">
<h2>{{item.title}}</h2>
<img src="{{firstImg}}" alt="">
<p>{{item.publishedDate}}</p>
<p>{{item.contentSnippet}}</p>
</span>
</div>
FeedCtrl.js:
var feeds = [];
angular.module('feedModule', [])
.factory('FeedLoader', function ($resource) {
return $resource('http://ajax.googleapis.com/ajax/services/feed/load', {}, {
fetch: { method: 'JSONP', params: {v: '1.0', callback: 'JSON_CALLBACK'} }
});
})
.service('FeedList', function ($rootScope, FeedLoader) {
this.get = function() {
var feedSources = [
{title: 'Breaking Muscle', url: 'http://breakingmuscle.com/feed/nowod.xml'},
{title: 'Precision Nutrition', url: 'http://www.precisionnutrition.com/feed'},
{title: 'Girls Gone Strong', url: 'http://www.girlsgonestrong.com/feed/'},
];
if (feeds.length === 0) {
for (var i=0; i<feedSources.length; i++) {
FeedLoader.fetch({q: feedSources[i].url, num: 10}, {}, function (data) {
var feed = data.responseData.feed;
feeds.push(feed);
});
}
}
return feeds;
};
})
.controller('FeedController', function ($scope, FeedList) {
$scope.feeds = FeedList.get();
$scope.$on('FeedList', function (event, data) {
$scope.feeds = data;
var findFirstImage = data[0].entries[0].content;
var firstImage = $(findFirstImage).find('img').eq(0).attr('src');
$scope.firstImg = firstImage;
});
});
Please see here: http://jsbin.com/xidik/1/edit or there http://jsbin.com/xidik/3/edit is finding image for each feeds.
Add the $q service to your 'FeedList' service, then in your FeedController iterate through your data when promise will is resolved to find image.
var app = angular.module('app', ['ngResource']);
var feeds = [];
app.factory('FeedLoader', function ($resource) {
return $resource('http://ajax.googleapis.com/ajax/services/feed/load', {}, {
fetch: { method: 'JSONP', params: {v: '1.0', callback: 'JSON_CALLBACK'} }
});
});
app.service('FeedList', function ($rootScope, FeedLoader, $q) {
this.get = function() {
var deferred= $q.defer();
var feedSources = [
{title: 'Breaking Muscle', url: 'http://breakingmuscle.com/feed/nowod.xml'},
{title: 'Precision Nutrition', url: 'http://www.precisionnutrition.com/feed'},
{title: 'Girls Gone Strong', url: 'http://www.girlsgonestrong.com/feed/'},
];
if (feeds.length === 0) {
for (var i=0; i<feedSources.length; i++) {
FeedLoader.fetch({q: feedSources[i].url, num: 10}, {}, function (data) {
var feed = data.responseData.feed;
feeds.push(feed);
deferred.resolve(feeds);
});
}
}
return deferred.promise;
};
});
app.controller('firstCtrl', function($scope, FeedList) {
FeedList.get().then(function(data){
$scope.feeds = data;
angular.forEach(data[0].entries, function(value) {
value.sapleImage =$(value.content).find('img').eq(0).attr('src');
});
})
});
I need parse the enclosure tag in order to get the url image. It's assumed I should get the MIXED OUTPUT with the json+xml code but I get a undefined value from the enclousure tag when I try parse it. I'm doing this like I saw at this post > Google Feed Loader API ignoring XML attributes < .In addition I tried to get the MIXED format writing the url manually but It doesn't work. There is my whole code. How could I know that Im getting the mixed json output?
var feeds = [];
var entryImageUrl = [];
angular.module('starter.controllers', ['ngResource','ngLocale'])
.factory('FeedLoader', function ($resource) {
return $resource('http://ajax.googleapis.com/ajax/services/feed/load', {}, {
fetch: { method: 'JSONP', params: {v: '1.0', callback: 'JSON_CALLBACK', output: 'json_xml'} }
});
})
.service('FeedList', function ($rootScope, FeedLoader) {
this.get = function() {
var feedSources = [
{title: 'Heraldo De Barbate', url: 'http://www.heraldodebarbate.es/rss/last'},
];
if (feeds.length === 0) {
for (var i=0; i<feedSources.length; i++) {
FeedLoader.fetch({q: feedSources[i].url, num: 10}, {}, function (data) {
var feed = data.responseData.feed;
**var entryImageUrl = feed.xmlNode.getElementsByTagName("enclosure")[i].getAttribute("url");**
feeds.push(feed);
});
}
}
return feeds;
};
})
.controller('FeedCtrl', function ($scope, FeedList,$timeout) {
$scope.update = function(){
$scope.feeds = FeedList.get();
$scope.$on('FeedList', function (event, data) {
$scope.feeds = data;
// $scope.entryImageUrl
console.log(feeds);
});
$timeout(function() {
$scope.$broadcast('scroll.refreshComplete');
}, 500);
}
})
How could I know that Im getting the mixed json output?
Use a test for tags within JSON:
function testMe(node)
{
return /</.test(JSON.stringify(node) )
}
then run it on the feed:
var mixed_format = testMe(feed);
and call another function which parses the data:
if (mixed_format)
{
mixed_parser(feed)
}
else
{
json_parser(feed)
}