angularjs - Trouble getting data from database within template file - javascript

I'm working on a blog like structured web app In AngularJS. Im trying to retrieve the user which is an other of a post and retrieve their display name dynamically as it loops through all the posts but I cant seem to retrieve data correctly.. This is what I have done so far.
Blog Controller:
uno.controller('newsCtrl', function($scope, $http, adbFactory){
$scope.derp = 'derp!!!!!';
adbFactory.get($http, 'get users 1', false).success(function(data){
$scope.user = data;
}).error(function(){
console.log('Errorrr');
});
$scope.init = function(){
adbFactory.get($http, 'get all blog_posts', true).success(function(data){
$scope.posts = data;
console.log($scope.posts);
});
};
$scope.getAuthor = function(_id) {
adbFactory.get($http, 'get users id ' +_id+ ' spec', false).success(function(data){
//$scope.author = data;
//console.log($scope.author);
return data;
});
};
});
If I console.log the data it shows the users perfectly given the author id which is in the database, but when i attempt to call the getAuthor function using the '{{ }}' scope i get a collage of errors... heres my blog template below.
Blog Template:
<div class="large-12 small-12 columns" ng-init="init()">
<div class="row">
<div class="large-12 small-12 columns" ng-repeat="topic in posts" style="margin-bottom:20px;">
<div id="news-post" class="panel animated fadeInUp">
<div class="row" ng-init="getAuthor(topic.author_id)">
<div class="large-2 small-2 columns">
<img src="{{ topic['thumb'] }}" alt="" style="border-radius:50%; height:100px; width: 150px;" />
</div>
<div class="left large-10 small-10 columns">
<div class="row">
<h2 class="post-title">{{topic['title']}} <p>Posted By, {{ getAuthor(topic.author_id).email }}</p></h2>
<p>{{ topic['body'] }}</p>
</div>
</div>
</div>
</div>
</div>
<hr>
</div>
</div>
not quite sure what the problem can be.. Any thing I'm missing?
UPDATE::
I recently updated my controller and factories to get a better scope of handling my data flow, my Controller now looks like this:
uno.controller('newsCtrl', function($scope, $http, adbFactory, $cacheFactory, unoFunctions){
$scope.init = function(){
adbFactory.get($http, 'get all blog_posts', true).success(function(data){
$scope.posts = data;
$scope.getUser = function(_id) {
$scope.userData = unoFunctions.getUser(_id);
//console.log($scope.userData);
return $scope.userData;
};
});
$scope.getTags = function(_id) {
var post = unoFunctions.getPost(_id);
var _tags = post.tags.split(',');
for(var i = 0; i < _tags.length; i++)
{
_tags[i] = _tags[i].trim();
}
return _tags;
};
$scope.getUserName = function(_id) {
$scope.userData = unoFunctions.getUser(_id);
return $scope.userData.display_name;
};
$scope.getUser = function(_id) {
$scope.userData = unoFunctions.getUser(_id);
//console.log($scope.userData);
return $scope.userData;
};
$scope.getUserName = function(_id) {
$scope.userData = unoFunctions.getUser(_id);
return $scope.userData.display_name;
};
};
});
the unoFunctions factory is wht I use now to handle certain requests from my database, and that is shown below.
uno.factory('unoFunctions', function(adbFactory, $http, $cacheFactory){
var fact = {};
var user = $cacheFactory('user');
var post = $cacheFactory('post');
fact.getUser = function(_id) {
if(!user.get(_id)){
adbFactory.get($http, 'get users id '+_id+' spec', false).success(function(data){
user.put(_id, data);
});
}
return user.get(_id);
};
fact.getPost = function(_id) {
if(!post.get(_id))
{
adbFactory.get($http, 'get blog_posts id '+_id+' spec', false).success(function(data){
post.put(_id, data);
});
}
return post.get(_id);
};
fact.loggedIn = function()
{
console.log('gfdg');
};
/*------------------------------*/
return fact;
});
And my template to output the result is this:
<div class="large-12 small-12 columns" ng-init="init()">
<div class="row">
<div class="large-12 small-12 columns" ng-repeat="topic in posts | filter:postTitle | orderBy:'-time' " style="margin-bottom:20px;">
<div id="news-post" class="panel animated fadeInUp" ng-init="getTags(topic.id)">
<div class="row" style="padding-bottom:0px;">
<div class="large-2 small-2 columns">
<img src="{{ topic['thumb'] }}" alt="" style="border-radius:50%; height:120px; width: 200px;" />
</div>
<div class="left large-10 small-10 columns">
<div class="row" style="padding-bottom:0px;">
<h2 class="post-title">
<a href="#/news/post/{{ topic['id'] }}">
{{topic['title']}}
</a>
<p style="font-size:13px; font-style:italic; color:#a5a5a5" class="right">{{ topic.time | timeago }} {{ }}</p>
<p style="font-weight:bold; font-style:italic; color:#aaa">Posted By, {{ getUser(topic.author_id).display_name }}</p></h2>
<p>{{ topic['body'] }}</p>
<div ng-repeat="tag in getTags(topic.id)"><span style="background:#ccc; margin:7px; padding:4px; border-radius:5px; font-size:12px" class="left">{{ tag }}</span></div>
<p class="right" style="background:#dedede; font-size:13px; padding:7px; border-radius:6px; color:#1985A1;">{{ topic.category }}</p
</div>
</div>
</div>
</div>
</div>
</div>
</div>
This works fine and returns the required results I'm looking for but I wish to get rid of the countless Error: [$rootScope:infdig] errors and keep my console clean.. I researched the error and it seems to be because when I call functions from the unoFunctions factory like, getUser, or getPost. it returns a new array each time or something like that which I guess throws things out of scope. I'm not entirely sure, and reason for this?

This binding
<p>Posted By, {{ getAuthor(topic.author_id).email }}</p>
assumes that getAuthor returns an object, but it doesn't, even with proper return statement - because asynchronous request takes place, and adbFactory chain will apparently return a promise, not an object. And doing adbFactory.get every time getAuthor bindings are being watched would be bad performance-wise - json result has to be parsed constantly, even with $http cache.
A suitable solution for caching and binding service results to the scope (and a precursor to full-blown model) is
var authors = $cacheFactory('authors');
$scope.getAuthor = function(_id) {
if (!authors.get(_id)) {
authors.put(_id, {});
adbFactory.get($http, 'get users id ' +_id+ ' spec', false).success(function(data){
authors.put(_id, data);
});
}
return authors.get(_id);
};

Related

Dynamically display comments with links inside using Angular JS

i have developed a comment system using Angular JS. Unfortunately if a user inserts a link in his comment, the link is not clickable in the displayed comment.
How can i achieve this ?
Here is my HTML code:
<section class="comment-list" ng-hide="loading" ng-repeat="comment in comments">
<article class="row">
<div class="col-md-2 col-sm-2 hidden-xs">
<figure class="thumbnail">
<img class="img-responsive" src="#{{ comment.user.avatar }}" />
</figure>
</div>
<div class="col-md-10 col-sm-10" style="padding-bottom: 10px;">
<div class="comment_panel panel-default arrow left">
<div class="panel-body">
<header class="text-left">
<div class="comment-user"><i class="fa fa-user"></i> #{{ comment.user.name }}</div>
<time class="comment-date"><i class="fa fa-clock-o"></i> #{{ comment.date }}</time>
</header>
<div class="comment-post">
<p ng-bind-html="sanitizedComment"></p>
</div>
</div>
</div>
</div>
</article>
The comment body is inside the #{{ comment.comment.content }}
Here is the angular controller:
angular.module('mainCtrl', [])
// inject the Comment service into our controller
.controller('mainController', function($scope, $http, $sce, Comment) {
// object to hold all the data for the new comment form
$scope.commentData = {};
$scope.sanitizedComment = $sce.trustAsHtml($scope.comment.comment.content);
// loading variable to show the spinning loading icon
$scope.loading = true;
// get all the comments first and bind it to the $scope.comments object
// use the function we created in our service
// GET ALL COMMENTS ==============
Comment.get()
.success(function(data) {
$scope.comments = data;
$scope.loading = false;
});
// function to handle submitting the form
// SAVE A COMMENT ================
$scope.submitComment = function() {
$scope.loading = true;
// save the comment. pass in comment data from the form
// use the function we created in our service
Comment.save($scope.commentData)
.success(function(data) {
// if successful, we'll need to refresh the comment list
Comment.get()
.success(function(getData) {
$scope.comments = getData;
$scope.loading = false;
});
})
.error(function(data) {
console.log(data);
});
};
// function to handle deleting a comment
// DELETE A COMMENT ====================================================
$scope.deleteComment = function(id) {
$scope.loading = true;
// use the function we created in our service
Comment.destroy(id)
.success(function(data) {
// if successful, we'll need to refresh the comment list
Comment.get()
.success(function(getData) {
$scope.comments = getData;
$scope.loading = false;
});
});
};
});
<div class="comment-post>
<p ng-bind-html="comment.comment.content"></p>
</div>
Should do the trick.

Unable to post ng-model data

I have an angular app that consists of a three tabbed form. Each tab is using its own controller and designated service.
When the submit button is pressed on the form, the function found in MainCtrl entitled $scope.postis suppose to post all form field data that was retrieved from each form fields ng-model.
On the server side, I receive the posted object that is formed in the Main Controller. This POST contains all the values for each object property except for work. I receive an empty object as a value for the work property.
Why am I unable to retrieve the work.comments ng-model found in the code for my template? Even when console loggin, I am unable to retrieve this item.
This is my first go at an Angular app and I am really trying to learn how to do things properly. If you happen to notice something inherently stupid, please do let me know.
Controller:
.controller('WorkCtrl', function ($scope, $ionicModal, TaskService, WorkService) {
$scope.work = {};
WorkService.add($scope.work);
});
Service:
.factory('WorkService', function() {
var work = {};
return {
add: function(data) {
work['work'] = data;
//work = data;
},
list: function() {
return work;
}
};
})
Template:
<div class="list" ng-controller="WorkCtrl">
<label class="item item-input item-floating-label">
<button class="button button-clear item-icon-right" ng-click="newTask()">New Task<i class="icon ion-ios-plus-outline"></i></button>
</label>
<label class="item item-input item-floating-label">
<span class="input-label">Comments</span>
<textarea placeholder="Comments" rows="6" ng-model="work.comments"></textarea>
</label>{{work | json}}
</div>
<div ng-controller="TaskCtrl">
<div ng-show="ifTasks()">
<div class="row header">
<div class="col tableRow">Task</div>
<div class="col tableRow">Edit</div>
<div class="col tableRow">Remove</div>
</div>
<div class="row" ng-repeat="task in tasks track by task.id">
<div class="col tableRow">{{task.choice}}</div>
<div class="col tableRow" ng-controller="WorkCtrl"><button class="button button-small button-balanced" ng-click="editTask({{task.id}})">Edit</button></div>
<div class="col tableRow"><button class="button button-small button-assertive" ng-click="del({{task.id}})">Delete</button></div>
</div>
</div>
</div>
Main Controller:
.controller('MainCtrl', function($scope, $http, SiteService, TaskService, WorkService, LabourService) {
$scope.toFetch = [];
var obj = {
site: SiteService.list(),
tasks: TaskService.list(),
work: WorkService.list(),
labour: LabourService.list()
};
$scope.post = function() {
console.log(obj);
$http({
url: 'http://localhost:1818/send/report',
method: 'POST',
data: obj,
headers: {'Content-Type': 'application/json'}
})
.then(function(data) {
console.log(data);
});
};
});

angular how to reload a controller

I have a categoriesPanel controller that on ng-click I want to show all the products belongings to that category inside my ng-controller productsPanel. The problem im having is that every time I click on the ng-click="selectorCategory" I get the all the products in the clicked category after I refresh the page.
<div class="col-md-6 m-t-10" ng-controller="productsPanel" style="padding-right:1px;">
<div class="panel panel-default" style="height: 700px">
<div class="panel-body">
<div ng-repeat="product in Products" class="productRow">
{{product.Product}}
</div>
</div>
</div>
</div>
<div class="col-md-3 m-t-10" ng-controller="categoriesPanel" style="padding-left: 0; padding-right: 5px">
<div class="panel panel-default" style="height: 700px">
<div class="panel-body">
<div ng-repeat="category in Categories" class="categoryRow">
{{category.Category}}
</div>
</div>
</div>
</div>
this is my angular script that is getting the right data from the backend but the data only shows in the producsPanel controller when i refresh the page. I want to data to show as soon as you do the ng-click.
app.controller('categoriesPanel', function($scope, $location, $http, $localStorage){
var CompanyId = $localStorage.Employee[0].CompanyId;
$http({
method : 'GET',
url : 'http://localhost:8888/categories/ajax_getCompaniesCategories',
params: {CompanyId: CompanyId}
})
.success(function(data){
$scope.Categories = data;
$localStorage.Categories = data;
});
$scope.selectedCategory = function(event){
$localStorage.CategoryId = $(event.target).data('id');
$http({
method : 'GET',
url : 'http://localhost:8888/products/ajax_getCategoryProducts',
params: {CategoryId: $localStorage.CategoryId}
})
.success(function(data){
$scope.Products = data;
$localStorage.Products = data;
});
}
});
app.controller('productsPanel', function($scope, $location, $http, $localStorage){
$scope.Products = $localStorage.Products;
});
/* END CONTROLLERS */
Maybe the product array you are pointing to gets clear when call to getcategoryproducts is made. Can you fix your callback for ajax_getCategoryProducts and change success to push elements into the array instead of reassignment.
.success(function(data){
$scope.Products.length=0;
data.forEach(function(p) {
$scope.Products.push(p);
});
$localStorage.Products = $scope.Products;
});

How do I update a view after ng-submit calls a factory function?

$scope.temp and $scope.description don't have values until ng-submit calls $scope.getWeather. I can log the values after submission, but can't update the view to display them. $scope.test is demonstrating that my view will only display "This is a DEFAULT value" and not update to "This is the NEW value" when $scope.getWeather is called. Thanks.
angular.module('forecastCtrl', ['weatherService'])
.controller('forecastController', function($http, $scope, Weather) {
//var vm = this;
$scope.test = 'This is a DEFAULT value';
$scope.getWeather = function(postData) {
Weather.get(postData)
.success(function(data) {
console.log(data);
$scope.test = 'This is the NEW value';
$scope.temp = data.query.results.channel.item.condition.temp;
$scope.description = data.query.results.channel.item.condition.text;
})
.error(function(error) {
console.log(error);
});
event.preventDefault();
};
// THIS IS THE FORM
<form name="getWeatherForm" action="#" ng-submit="getWeather(postData)" class="small-10 large-6 small-centered large-centered columns">
<div class="row collapse">
<div class="small-9 columns">
<input type="text" placeholder="Philadelphia, PA" ng-model="postData.city">
</div>
<div class="small-3 columns">
<button type="submit" class="button postfix">Go</button>
</div>
</div>
</form>
//THIS IS THE FACTORY
angular.module('weatherService', [])
.factory('Weather', function($http) {
return {
get: function(location) {
location = location.city;
location = location.replace(/\s/g, '');
// do error handling
return $http.get('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22'+location+'%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys');
}
}
});
// THE VIEW
<main id="content">
<div class="row">
<div class="small-12 large-12 columns">
<section class="wrapper">
{{ test }}
<h1>{{ forecast.temp }}</h1>
<h2>{{ forecast.description }}</h2>
</section>
</div>
</div>
The code is working, but the repsonse does not have the assumed properties when the city is not provided or wrong city is provided. So maybe use ng-required, as the code will fail if the postData.city is not set
http://plnkr.co/edit/7F3EUMyAXtAlBR9CGWb0?p=preview
.success(function(data) {
console.log(data);
$scope.test = 'This is the NEW value';
$scope.temp = data.query.results.channel.item.condition.temp;

Template is compiled before the result is returenf from $http service

Hi I am trying to retrieve data from the server using $http, and correct data is being retrieved from the service, the data is -
[{
"URL":"someimg.jpg",
"TITLE":"Test Demo",
"DATE_ADDED":"2014-02-08 00:46:00",
"SUMMARY":"this is summary"
}]
the template that I wrote is as follows -
<article class="span8" ng-controller="allBlogs">
<div ng-show="success">
<div ng-repeat="blog in blogs.data">
<div class="row">
<div class="span3">
<img ng-src="{{blog['URL']}}" alt="" />
</div>
<div class="span5" ng-repeat-end>
<h4>{{blog.TITLE}}</h4>
<p>{{blog.DATE_ADDED}}</p>
<p>{{blog.SUMMARY}}</p>
</div>
</div>
</div >
</div>
</article>
the controller for the above template is as follows -
pk.controller("allBlogs", function($scope, $http, BlogsHandler){
$scope.success = false;
(function(){
BlogsHandler.getAllBlogs().success(function(data){
console.log(data);
$scope.success = true;
$scope.blogs = data.data;
});
})();
});
I am trying to set the success as true when the service returns data and thus the remaining part of the template should run. But this is not happening. Is it not that any change to $scope variable is being watched by the framework itself?
Help needed. I even tried with ng-switch with no effect.
Thanks
You assign data.data to $scope.blogs, so you don't need to add .data before blogs again.
$scope.blogs = data.data;
So, try this:
<div ng-repeat="blog in blogs track by $index">
<div class="row">
<div class="span3">
<img ng-src="{{blog.URL}}" alt="" />
</div>
<div class="span5">
<h4>{{blog.TITLE}}</h4>
<p>{{blog.DATE_ADDED}}</p>
<p>{{blog.SUMMARY}}</p>
</div>
</div>
</div >

Categories

Resources