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');
});
})
});
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'm trying to make a search in an http call with a different value depending on the view that I'm in.
My factory looks like this:
.factory('SearchService', ['$http','$filter', function($http, $filter) {
var service = {
getAllExhibitors : function () {
var searchindex = 'Berliner';
var url = '...';
var config = {
params: {
search: searchindex
},
cache:true
};
$http.get(url, config).then(function (data) {
service.datafairs = data.data.rows;
...
});
}...
As you can see I'm passing a hardcoded variable searchindex as parameter for the search.
Could I set this variable depending on the view I'm in?
My config for the router looks like this:
.config(function($stateProvider) {
var berlinerState = {
name: 'berliner',
url: '/berlinerliste/',
views: {
'header': {
templateUrl: 'header.htm'
},
'main':{
templateUrl: 'bl2017.htm'
}
}
}
var koelnerState = {
name: 'koelner',
url: '/koelnerliste/',
views: {
'header': {
templateUrl: 'header.htm'
},
'main':{
templateUrl: 'kl2017.htm'
}
}
}
...
For example, that on /berlinerliste, searchindex = X and on /koelnerliste, searchindex = Y
Any tips?
From the controller when you call your factory, you could be pass the actual state name and based on this value define the searchIndex on the getAllExhibitors method.
getAllExhibitors : function (stateName) {
var searchindex = '';
var url = '...';
var config = {
params: {
search: searchindex
},
cache:true
};
if(stateName === 'berliner'){
config.params.search = 'asdf'
}
....
$http.get(url, config).then(function (data) {
service.datafairs = data.data.rows;
...
});
}...
and from your controller inject the $state service and send to the method the value of $state.current.name
Another way it is inject the $state service directly on your service, like this:
.factory('SearchService', ['$http','$filter','$state', function($http, $filter, $state){
var service = {
getAllExhibitors : function () {
var searchindex = 'Berliner';
var url = '...';
var config = {
params: {
search: searchindex
},
cache:true
};
if($state.current.name === 'berliner') {
config.params.search = 'asdf'
}
....
$http.get(url, config).then(function (data) {
service.datafairs = data.data.rows;
...
});
}...
When working with asynchronous APIs such $http, it is best to return promises:
app.service('SearchService', function($http, $filter) {
this.getAllExhibitors = function (searchArg) {
var searchindex = searchArg || 'Berliner';
var url = '...';
var config = {
params: {
search: searchindex
},
cache:true
};
//RETURN promise
͟r͟e͟t͟u͟r͟n͟ $http.get(url, config).then(function (response) {
͟r͟e͟t͟u͟r͟n͟ response.data.rows;
});
};
});
Then in the controller, extract data from the promise:
app.controller("viewController", function($scope, SearchService, $state) {
var searchArg = $state.current.name;
var promise = SearchService.getAllExhibitors(searchArg);
promise.then(function(rows) {
$scope.rows = rows;
});
});
Also notice the the getAllExhibitors function has been modified to accept a search argument.
The return statement is a very useful thing that isn't used enough.
Im trying to push each data from json into new array, because a wanna make a graph, but it doesn't works.
What I expect is like :
f = { "FAKULTAS":"01/FKIP",
"FAKULTAS":"02/FMIPA",
"FAKULTAS":"03/FISIP" }
g = { "MASA20131":283133,
"MASA20131":2419,
"MASA20132":58719 }
This is my Json File:
{
"DARIMASA":"20131",
"KEMASA":"20142",
"ISIMASA":
[{"masa":"20131"},{"masa":"20132"},{"masa":"20141"},{"masa":"20142"}],
"DATAFAKULTAS":
[
{
"FAKULTAS":"01/FKIP",
"MASA20131":283133,
"MASA20132":26746,
"MASA20141":261238,
"MASA20142":245722
},
{
"FAKULTAS":"02/FMIPA",
"MASA20131":2419,
"MASA20132":29,
"MASA20141":2706,
"MASA20142":3207
},
{
"FAKULTAS":"03/FISIP",
"MASA20131":53312,
"MASA20132":58719,
"MASA20141":55047,
"MASA20142":53745
}]
}
Controller :
.controller("RegMhsSemesterCtrl", function ($scope, $http, chartBar4) {
$scope.data = {};
$http.get('data/RegPerSemester.json')
.success(function (data) {
var axis2 = [],seriesA = [],seriesB = [],seriesC = [],seriesD = [];
data.forEach(function(row) {
axis2.push(row.FAKULTAS);
seriesA.push(row.MASA20131);
seriesB.push(row.MASA20132);
seriesC.push(row.MASA20141);
seriesD.push(row.MASA20142);
});
$scope.data.f=axis2;
$scope.data.g=seriesA;
$scope.data.h=seriesB;
$scope.data.i=seriesC;
$scope.data.j=seriesD;
console.log($scope.data);
var i= chartBar4('chartbar4',$scope.data);
window.onresize=function ()
{
i.resize()
}
})
.error(function (error) {
$scope.data.error = error;
});
})
you can use the following code:
.controller("RegMhsSemesterCtrl", function ($scope, $http, chartBar4) {
$scope.data = {};
$http
.get('data/RegPerSemester.json')
.success(function (data) {
var DATAFAKULTAS = data.DATAFAKULTAS;
var axis2 = [],seriesA = [],seriesB = [],seriesC = [],seriesD = [];
for(var i=0; i<DATAFAKULTAS.length; i++) {
axis2.push({
"FAKULTAS": DATAFAKULTAS[i].FAKULTAS
});
seriesA.push({
"MASA20131": DATAFAKULTAS[i].MASA20131
});
.....................................................
.....................................................
}
});
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);
};
})
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)
}