AngularJS scope refresh on post to API through restangular - angularjs

I have a controller which loads data via Restangular like so:
var oneTopic = Restangular.one('topics', topic.id);
oneTopic.get({}, {"Authorization" : localStorageService.get('***')}).then(function(topic) {
topic.getList('comments', {}, {"Authorization" : localStorageService.get('***')}).then(function(comments){
$scope.comments = comments;
//console.log($scope.comments);
});
});
And then a function which posts a new comment and one that deletes a comment.
$scope.delComment = function(comment_id, author_id){
var comment = Restangular.one('comments', comment_id);
comment.remove({author_id: author_id}, {"Authorization" : localStorageService.get('***')}).then(function(){
// need to perform refresh here
});
};
$scope.postComment = function(mood) {
$scope.commentData.mood = mood;
comments.post($scope.commentData, {}, {"Authorization" : localStorageService.get('***')}).then(function(response){
// need to perform refresh here
}, function(response){
$scope.error = response.data.message;
})
};
How would I refresh the comments scope without reloading the page? The data is being populated in the HTML with an
<div ng-repeat="comment in comments">

Modify the existing array referenced by $scope.comments and the data binding will take care of it.
For example:
$scope.delComment = function(comment_id, author_id) {
var comment = Restangular.one('comments', comment_id);
comment.remove({ author_id: author_id }, { "Authorization": localStorageService.get('***')
}).then(function() {
// Some remove-from-array implementation, for example:
var c = $scope.comments;
for(var i = 0, l = c.length; i < l; i++) {
if (c[i].comment_id === comment_id) {
c = c.splice(i, 1);
break;
}
}
});
};

Related

JSON won't save on scope AngularJS

i have a problem with saving JSON on a scope, I have already a function saving a JSON into a scope and works perfectly but the second one won't save...
servicoLeituraPosts.php returns JSON with data
servicoLeituraComments.php returns JSON with data
both send JSON through URL correctly, and the first shows data on scope, but the second one doesn't and it's done exactly like the first one, so I don't understand what is going on.
1st one saves JSON into $scope.posts, it has data and i can print it
2nd one saves JSON into $scope.comments, if i print it, it is blank? Why? Thank you for help but I'm a beginner in AngularJS.
<script>
var app = angular.module('postsApp', []);
var interval;
app.controller('postsCtrl', function($scope) {
$scope.toggle = false;
$scope.texto = [];
$scope.comment = [];
$scope.comment = "";
$scope.comments = [];
$scope.posts = [];
$scope.texto = "";
$scope.idPost = 0;
$scope.showBox = function(p){
p.toggle = !p.toggle;
if(interval == 0){
interval = setInterval("angular.element($('#postsApp')).scope().servicoLeituraPosts()",1000);
}else{
clearInterval(interval);
interval = 0;
}
$scope.servicoLeituraComments(p);
console.log($scope.comments);
console.log($scope.posts);
};
$scope.iniciaTimer = function(){
interval = setInterval("angular.element($('#postsApp')).scope().servicoLeituraPosts()",1000);
};
$scope.servicoLeituraPosts = function(){
$.getJSON(
"servicoLeituraPosts.php",
{
},
function(jsonData)
{
$scope.posts = jsonData;
$scope.$apply();
});
};
$scope.servicoLeituraComments = function(p){
$.getJSON(
"servicoLeituraComments.php",
{
"idPost": p.idPost
},
function(jsonData)
{
$scope.comments = jsonData;
$scope.$apply();
});
console.log($scope.comments);
};
$scope.addPost = function(){
$.post(
"addPostRest.php",
{
"texto" : $scope.texto
},
function(dados)
{
$scope.texto = dados.indexOf("OK") >= 0 ? "" : "FALHOU";
$scope.$apply();
}
);
};
$scope.addLike = function(idPost){
$.post(
"addLike.php",
{
"idPost" : $scope.idPost = idPost
},
function(dados)
{
$scope.texto = dados.indexOf("OK") >= 0 ? "" : "FALHOU";
$scope.$apply();
}
);
};
$scope.addComment = function(p){
$.post(
"addComentarioRest.php",
{
"comment" : p.comment,
"idPost" : p.idPost
},
function(dados)
{
$scope.texto = dados.indexOf("OK") >= 0 ? "" : "FALHOU";
$scope.$apply();
}
);
};
});
</script>
Found the solution, apparently there was a problem with the parameter recieved on POST which made the JSON invalid having no data
It looks like you are calling console.log($scope.comments); synchronously after calling $.getJSON(...), rather than waiting for the jsonData to be returned. At this point the $scope is yet to be updated.
Try moving the console.log into the callback:
function(jsonData)
{
$scope.comments = jsonData;
$scope.$apply();
console.log($scope.comments);
});

Ionic Pagination starting

I am trying to create a pagination feature but I feel stuck. I am not sure if I am on the right track...
in my view, I have an ng-repeat=" res in result", and at the end of the page i placed the following:
<ion-infinite-scroll on-infinite="loadMore()" distance="1%"></ion-infinite-scroll>
then in the controller, i wrote this:
var i=1;
$http.get( "http://website/search/"+i).success(function(response){
i++;
$scope.result=(response)
});
}
each pages returns a json containing 15 elements. What I want to do is when i reach the end, I want to load the next 15 in the result to be displayed.
You have to fetch next 15 item in loadMore function in controller as you write on-infinite="loadMore()" in ion-infinite-scroll
Write function as follow in your controller
$scope.result = [];
var i=1;
$scope.loadMore = function(){
$http.get( "http://website/search/"+i).success(function(response){
i++;
$scope.result.push(response);
});
}
Check Example
Hears how I have implemented infinite-scroll in my app
<ion-infinite-scroll ng-if="!loadMorePeople" on-infinite="loadPeople()" distance="1%"></ion-infinite-scroll>
loadPeople() loads all the scrolled data, it's code is bellow
$scope.loadMorePeople=false;
$scope.loadPeople = function() {
if($scope.peoples != null){
$http({
method: "get",
url: baseUrl+"company-members?page="+$scope.pagePeople,
withCredentials: true,
headers: {
'Accept' : 'application/json, text/plain, */*',
'Authorization' : ''+window.localStorage.getItem("token_type")+' '+window.localStorage.getItem("token")
}
})
.success(function(data) {
if(data.length > 0){
var newPeople = data;
$scope.temp = $scope.peoples.concat(newPeople);
$scope.peoples = arrayUnique($scope.temp, 'id');
function arrayUnique(collection, keyname) {
var output = [],
keys = [];
angular.forEach(collection, function(item) {
var key = item[keyname];
if(keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});
return output;
};
++$scope.pagePeople;
$scope.$broadcast("scroll.infiniteScrollComplete");
}else{
$scope.loadMorePeople=true;
$scope.$broadcast("scroll.infiniteScrollComplete");
}
})
.error(function(data, status) {
});
}
$scope.$broadcast("scroll.infiniteScrollComplete");
};
I too had the same problem as you for some reason .push() was not working so I did this workaround.
I took the data checked if it's not null in if(data.length > 0){} and then used .concat(newPeople) to merge them and finally used arrayUnique($scope.temp, 'id') to make sure that there is no duplicate entity.
It's also a good idea to use ng-if="!loadMorePeople" it help to stop the call if there is no data left to fetch else the call will continously go on.
I hope this solves your problem. Let me know if you need any help :D

Variables between factories in angular.js

I'm currently learning angular and have hit a roadblock.
The second factory (shown below) makes an http request like this: http://example.com/api/get_post/?post_id=7129&callback=JSON_CALLBACK');
I want the post ID to be a variable. So depending on which blog title is clicked, I can pass the correct variable into that http request.
In other words, I guess I want to take a result from the first factory (blogAPIservice) and use it in the second factory.
Makes sense??
<!-- FACTORIES -->
angular.module('blogApp.services',[])
.factory('blogAPIservice',function($http) {
var blogAPI = [];
var blogs = $http.jsonp('http://example.com/api/get_recent_posts/?count=10&callback=JSON_CALLBACK');
blogs.success(function(data) {
$.each(data.posts, function(i, blog) {
var fromNow = moment(blog.date).fromNow();
blogAPI.push({
url: blog.url,
title: blog.title,
excerpt: blog.excerpt,
date : fromNow,
id: blog.id
})
});
});
var factory = {};
factory.getBlogs = function () {
return blogAPI;
};
return factory;
})
.factory('singlePostService',function($http) {
var singleAPI = [];
var postID = '7129';
var singlePost = $http.jsonp('http://example.com/api/get_post/?post_id=7129&callback=JSON_CALLBACK');
singlePost.success(function(data) {
singleAPI.push({
title: data.post.title,
content: data.post.content
})
});
var factory = {};
factory.getSinglePost = function () {
return singleAPI;
};
return factory;
})
And here are the controllers:
angular.module('blogApp.controllers', [])
.controller('resultsController',function($scope, blogAPIservice) {
$scope.keywordFilter = null;
$scope.blogs = [];
init();
function init() {
$scope.blogs = blogAPIservice.getBlogs();
}
function grabID() {
$(this).attr('rel');
}
})
.controller('singlePostController',function($scope, singlePostService) {
$scope.keywordFilter = null;
$scope.singlePost = [];
init();
function init() {
$scope.singlePost = singlePostService.getSinglePost();
}
})
And finally the markup:
<li ng-repeat="blog in blogs">
{{ blog.title }}
</li>
You can inject the first service into the second one like this:
.factory('singlePostService',function($http, blogAPIservice) {
//Do something with blogAPIservice
}
For more information about depenency injection read the docs

Angularjs how to stop infinity scroll when server has no more data to send

Based on THIS example which I have modified with an Ajax request to get the data Im struggling to find a way to stop it when the server has no more data to send.
I have tried to add a boolean variable in a service, and a $watch method in the directive but it is not working.
Is there a simple way to to achieve that ?
This is not my code but if there is no easy answer I can post my code with the changes I have done.
thanks for your help.
<div id="fixed" when-scrolled="loadMore()">
<ul>
<li ng-repeat="i in items">{{i.id}}</li>
</ul>
</div>
function Main($scope) {
$scope.data = { comments : [] }
$scope.loadMore = function(){
$http({
url: '/comment/next',
method: "POST"
})
.success(function(data){
for(var i=0; i<data.length; i++){
$scope.data.comments.push(data[i]);
}
});
}
}
angular.module('scroll', []).directive('whenScrolled', function() {
return function(scope, elm, attr) {
var raw = elm[0];
elm.bind('scroll', function() {
if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
scope.$apply(attr.whenScrolled);
}
});
};
});
I can only guess as to a solution without seeing more of your code (specifically what is returned by $http results), but I believe this sort of thing could work, depending on the structure of a comment object.
function Main($scope) {
$scope.data = { comments : [] }
$scope.scrollComplete = false;
$scope.loadMore = function(){
if($scope.scrollComplete || $scope.loading) { return; }
$scope.loading = true;
$http({
url: '/comment/next',
method: "POST"
})
.success(function(data){
for(var i=0; i<data.length; i++){
var totalComments = $scope.data.comments.length;
if($scope.data.comments[totalComments - 1].someID === data[i].someID){
$scope.scrollComplete = true;
}else{
$scope.data.comments.push(data[i]);
}
}
$scope.loading = false;
}).error(function(){ $scope.loading = false });
}
}
Just bear in mind that a solution like this isn't really elegant. What I like to do is allow an item ID to be passed to the API (i.e. your /comment/next), and treat that as the last grabbed item. So the API will only give me back everything after that. Using that method, you would simply have to pass the last comment ID to the API.

AngularJS - Append to a model with a $resource

I have this service:
factory('Post', function($resource) {
return $resource('/api/post.json', {},
{
query: {method:'GET', isArray: false}
}
);
})
And I have this controller:
function PostsCtrl($scope, Post) {
// init
$scope.page = 0;
$scope.page_has_next = true;
$scope.loadMore = function() {
if($scope.page_has_next) {
$scope.posts = Post.query({page: ++$scope.page},
function(data) {
$scope.page_has_next = data.has_next;
}
);
}
}
$scope.loadMore();
}
This works just fine, each time loadMore() is executed the model gets updated with the next page until there are no more pages. However, I want to append the new set of posts to the current model instead of replacing it, how can I do that?
Assuming that posts is a array:
$scope.posts = $scope.posts.concat(Post.query({page: ++$scope.page})
This will only work if the new posts has no duplicates with the old posts. If there are duplicates, you have to traverse the array and push only new posts.

Resources