AngularJs - Execute Function in ng-repeat - javascript

My Web-App Should get images from server, show them and and give possibility to vote for Like it or Not.
Votes will be stored on DB.
my Controller :
$scope.beginSearch = function () {
$http
.get("http://example?q=" + $scope.search )
.then(function (response) {
$scope.url = response.data.data;
});
};
<tr ng-repeat="x in url">
<th>
<img src="{{x.images}}"></img>
<div class="well">
<i class="fa fa-thumbs-o-up fa-2x vertical-align" ng-click="vote_up(x.id)"></i>
<i class="fa fa-thumbs-o-down fa-2x vertical-align" ng-click="vote_down(x.id)" ></i>
</div>
</th>
</tr>
I was hoping to use a function in every ng-repeat, which would return
votes for like
{{ return_vote(x.id)}}
But it doesn't work, and as far I see, I should not use functions in html,
if they are not in ng-click functions.
ng-init also doesn't work.
Could anyone provide me help, how could I solve my problem?
Images are on some website, I just get them by using their WEB-API, so they doesn't have API for votes, I need to do it myself.

You can call your function inside brackets {{yourFunction(x.id)}} and add the logic to get the votes inside.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.url = [{
images: "http://lorempixel.com/g/100/100/",
id: 1
}, {
images: "http://lorempixel.com/100/100/",
id: 2
}]
$scope.getVotes = function(id){
//logic to get number of votes
return id * 5;
}
$scope.vote_up = function(id){
console.log("Vote up id " + id);
}
$scope.vote_down = function(id){
console.log("Vote down id " + id);
}
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="x in url">
<img src="{{x.images}}" />
<p>{{getVotes(x.id)}} votes</p>
<i class="fa fa-thumbs-o-up fa-2x vertical-align" ng-click="vote_up(x.id)"></i>
<i class="fa fa-thumbs-o-down fa-2x vertical-align" ng-click="vote_down(x.id)"></i>
</div>
</body>

Since you can't have the votes in the API you could alternatively create a service to get all the votes at once and then create some logic to match them to images.
e.g.
$scope.images = [];
var votes = [];
activate();
function activate() {
getImages().then(function () {
getVotes().then(function () {
matchVotesToImages();
//Now we have a property 'votes' in each image object which we can use in ng-repeat
});
});
}
function getVotes() {
var deferred = $q.defer();
$http.get('theUrl').then(success, fail);
function success(res) {
votes = res;
deferred.resolve();
}
function fail(res) {
console.log("Error");
console.log(res);
}
return deferred.promise;
}
function getImages() {
var deferred = $q.defer();
$http.get('theUrl').then(success, fail);
function success(res) {
$scope.images = res;
deferred.resolve();
}
function fail(res) {
console.log("Error");
console.log(res);
}
return deferred.promise;
}
function getIndex(array, property, valueToCompare) {
var i = 0;
var len = array.length;
for (i; i < len; i++) {
if (array[i][property] == valueToCompare) {
return i;
}
}
return -1;
}
function matchVotesToImages() {
var i = 0;
var len = $scope.images.length;
for (i; i < len; i++) {
//We pick need the votes of this specific image so
var indexAtVoteArray = getIndex(votes, 'id', $scope.images[i].id);
if (indexAtVoteArray != -1)
$scope.images.votes = votes[indexAtVoteArray];
else
$scope.images.votes = 0;
}
}

Thanks for answer.
$scope.vote_get = function (id) {
$http({
method: "GET",
url: "vote.php",
data: {
'id': id
},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
.then(function (response) {
return response.data;
});
};
When I used this function to get votes, or return anything
, It does infinite loop.
Maybe I'am trying to do in wrong way, then please give me tips how to do that.
I'am just sure, that I need to send ID of image to .php file, this file will connect to database and return votes for provided ID.
Vote_up and Vote_down functions are same, they just POST data but seem to work ok.
Thanks
So, no one has idea :(?

Related

how passing ng-bind values in to a variable at asp.net core view?

I have a tag like this :
<a data-ng-click="showform(#item.CategoryId)">
I have a variable "catid" in razor...
#{int catid; }
I want save value in 'catid'
this my js code :
app.controller('Result', function ($scope) {
$scope.CatId = 0;
$scope.showform = function (id) {
$scope.CatId = id;
}
});
i want to use CatId for a linq code and show category name at view
Can you give me a sample code?
Following is a working example, you can refer to it.
<div ng-app="myApp" ng-controller="Result">
#foreach (var item in Model)
{
<a data-ng-click="showform(#item.CategoryId)">CategoryId is #item.CategoryId</a>
<br />
}
<h2>Name of selected Category is {{CatName}}</h2>
</div>
Make request(s) using AngularJS $http service
<script>
var app = angular.module('myApp', []);
app.controller('Result', function ($scope, $http) {
$scope.CatId = 0;
$scope.CatName = "";
$scope.showform = function (id) {
$scope.CatId = id;
$http.get("/GetCategoryNameById?catid=" + id)
.then(function (response) {
$scope.CatName = response.data;
//your code logic here based on your actual requirement
});
}
});
</script>
My GetCategoryNameById action method for testing purpose
[HttpGet("GetCategoryNameById")]
public IActionResult GetCategoryNameById(int catid)
{
//your code logic here
//query data based on received catid
var category = _dbcontext.Categories.Where(c => c.CategoryId == catid).FirstOrDefault();
return Ok($"{category.CategoryName}");
}
Test Result
Maybe you can use this way.
<input type="hidden" name="catid" id="catid" value="{{Catid}}" />
When you submit form this value passed to asp.net core.

Data Getting Repeated In DIV using Angular JS HTML

I am trying to create Just the way Facebook Post gets display. Here Conversation Message Contains the list of Post and on-click of the Post get-comments is getting Called which will fetch all the Comments as well as Reply corresponding to that Comment.
<div ng-repeat="coversationMessage in coversationMessageList">
<div ng-click="getComments(coversationMessage.channel_message_ID)">
<div>{{coversationMessage.date_time}}</div>
<div>{{coversationMessage.channel_message}}</div>
<div ng-if='commentList.length!=0'>
<div ng-repeat="comment in commentList">
<div>{{comment.date_time}}</div>
<div><b>{{comment.channel_message}}</b></div>
<div ng-if="commentMsg.replyCount> 0">
<div><a ng-click="showhideReply($index+1);$event.stopPropagation()">{{commentMsg.replyCount}}Replies</a></div>
<div class="mailText" ng-repeat="replyMessage in commentMsg.replyList">
<div>{{replyMessage.date_time |formatDateTime}}</div>
<div>{{replyMessage.channel_message}}</div>
</div>
</div>
</div>
</div>
</div>
Get Post Method will Populate the coversationMessageList (Array)
$scope.getPost = function(channel_thread_id) {
var promise = dashboardServices.getConversation(channel_thread_id);
promise.then(function(data) {
$scope.coversationMessageList = data.data;
}).catch(function(error) {
console.log("Error in fetching Conversation " + error);
});
}
Get Comments Will Populate commentList, replyCount and replyList
$scope.getComments = function(channel_thread_id) {
var promise = dashboardServices.getConversation(channel_thread_id);
promise.then(function(data) {
$scope.commentList = data.data;
console.log(JSON.stringify(data.data));
// This foreach method is to show comment reply for facebook
angular.forEach($scope.commentList, function(comment) {
if (comment.channel_message_ID) {
var channel_thread_id = comment.channel_message_ID;
var promise = dashboardServices.countReplyOnComment(channel_thread_id);
promise.then(function(data) {
$scope.commentMsg = {};
$scope.commentMsg = comment;
$scope.commentMsg.replyCount = {};
$scope.commentMsg.replyList = {};
$scope.countReply = data.data.length;
$scope.commentMsg.replyCount = $scope.countReply;
$scope.commentMsg.replyList = data.data;
comment = $scope.commentMsg;
console.log(comment);
}).catch(function(error) {
});
}
});
}).catch(function(error) {
});
}
The Problem is when i click on a Particular div the Comments and the reply is getting reflected to all the other div
Move the commentList into coversationMessage ...
Try the below code :
<div ng-repeat="coversationMessage in coversationMessageList">
<div ng-click="getComments(coversationMessage)">
<div>{{coversationMessage.date_time}}</div>
<div>{{coversationMessage.channel_message}}</div>
<div ng-if='coversationMessage.commentList && coversationMessage.commentList.length!=0'>
<div ng-repeat="comment in coversationMessage.commentList">
<div>{{comment.date_time}}</div>
<div><b>{{comment.channel_message}}</b></div>
<div ng-if="commentMsg.replyCount> 0">
<div><a ng-click="showhideReply($index+1);$event.stopPropagation()">{{commentMsg.replyCount}}Replies</a></div>
<div class="mailText" ng-repeat="replyMessage in commentMsg.replyList">
<div>{{replyMessage.date_time |formatDateTime}}</div>
<div>{{replyMessage.channel_message}}</div>
</div>
</div>
</div>
</div>
</div>
The service :
$scope.getComments = function (coversationMessage) {
var channel_thread_id = coversationMessage.channel_message_ID;
var promise = dashboardServices.getConversation(channel_thread_id);
promise.then(function (data) {
coversationMessage.commentList = data.data;
console.log(JSON.stringify(data.data));
// This foreach method is to show comment reply for facebook
angular.forEach(coversationMessage.commentList, function (comment) {
if (comment.channel_message_ID) {
var channel_thread_id = comment.channel_message_ID;
var promise = dashboardServices.countReplyOnComment(channel_thread_id);
promise.then(function (data) {
$scope.commentMsg = {};
$scope.commentMsg = comment;
$scope.commentMsg.replyCount = {};
$scope.commentMsg.replyList = {};
$scope.countReply = data.data.length;
$scope.commentMsg.replyCount = $scope.countReply;
$scope.commentMsg.replyList = data.data;
comment = $scope.commentMsg;
console.log(comment);
}).catch(function (error) {
});
}
});
}).catch(function (error) {
});
}

Angular 1.5 when select all in input checkbox, value won't bind to model

Hi I am using https://vitalets.github.io/checklist-model/ to bind data from a checkbox to the model. When a user selects a checkbox it successfully binds data. However, I need the options to also "select all" I have followed the instructions in the documentation and have tried mapping all the value in the array so when the user "selects all" all the values are binded into the model. Instead of that happening I get an array with value of null. Here is how the flow works
1)init() function is called returning data when the user loads the application
2)user selects an air_date
3)user gets syscode data return after ng-options getSyscodes() is called
4)A user can select multiple syscodes
5)User can "select all" this is where my issue is, when I call selectAll(), instead of returning every value in array, the array returns as "null" and I can't make a call to the API.
I would appreciate any suggestions thanks!
Here is my HTML
Array Structure of Every Object
{syscode:1233,readable_name: "MTV"}
<form>
<div class="form-group">
<pre>Selected Model: {{rc.selections.syscode}} </pre>
<label>Syscode</label>
<!-- <select class="form-control" ng-options="syscode.readable_name for syscode in rc.dropdowns.syscodes" ng-model="rc.selections.syscode" ng-disabled="rc.dropdowns.syscodes.length === 0">
</select> -->
</div>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" style="width:214px;height:33px;font-size:15px;margin-left:-16px;"><i class="fa fa-caret-down pull-right" aria-hidden="true" style="width:1em;"></i></button>
<ul class="dropdown-menu">
<button class="btn btn-success btn-md" ng-click="rc.selectAll()"><i class="fa fa-check" aria-hidden="true"></i>Select All</button>
<button class="btn btn-danger btn-md" ng-click="rc.unselectAll()"><i class="fa fa-times" aria-hidden="true"></i>Unselect All</button>
<li ng-repeat="value in rc.dropdowns.syscodes">
<input type="checkbox" checklist-model="rc.selections.syscode" checklist-value="value.syscode" ng-checked="rc.selections.checked" /> {{value.readable_name}}</li>
</ul>
</form>
And Controller
ReportsController.$inject = ['ReportService','$window', '$q'];
function ReportsController(ReportService, $window, $q){
//Sorting Values
var ctrl = this;
//Initial State Values
ctrl.results = [];
ctrl.pageDone = false;
ctrl.loading_results = false;
ctrl.search_enabled = false;
ctrl.searching = false;
//Initial data arrays
ctrl.dropdowns = {
air_dates:[],
syscodes:[],
syscodeArray:[]
};
ctrl.test = null;
//Data binding objects
ctrl.selections = {
air_date:null,
checked: null,
syscode:null,
getAll: false
};
//Get Syscodes
ctrl.selectSyscode = function(){
ctrl.search_enabled = true;
ctrl.dropdowns.syscodes = [];
ctrl.dropdowns.syscodeArray = [];
ReportService.getSyscodes(ctrl.selections).then(function(response){
ctrl.dropdowns.syscodes = response.data;
//This line below enables select all in UI
ctrl.dropdowns.syscodeArray.push(response.data);
console.log("SyscodeArray", ctrl.dropdowns.syscodeArray);
});
};
// Select All Logic
ctrl.selectAll = function(){
var newitems = [];
angular.forEach(ctrl.dropdowns.syscodes, function(syscode) {
ctrl.selections.checked = 1;
newitems.push(syscode.syscode);
});
ctrl.selections.syscode = newitems;
}
// Unselect All
ctrl.unselectAll = function(){
angular.forEach(ctrl.dropdowns.syscodeArray, function(user) {
ctrl.selections.checked = 0;
});
ctrl.selections.syscode = [];
}
//Search Logic by Syscode and Air_Date
ctrl.search = function () {
var defer = $q.defer();
if (ctrl.search_enabled) {
ctrl.searching = true;
ctrl.error = false;
ctrl.sort_by = {
col: 'market',
reverse: true
};
ctrl.filters = undefined;
ReportService.getAssets(ctrl.selections).then(function (response) {
ctrl.results = response.data;
console.log("It worked!!!",response.data);
ctrl.searched_once = true;
ctrl.searching = false;
defer.resolve('searched');
}, function (error) {
defer.reject('search-error');
ctrl.error = true;
ctrl.searching = false;
ctrl.error_data = error;
});
} else {
defer.resolve('no-search');
}
return defer.promise;
};
//Calls initial air dates
var init = function(){
ReportService.getAirDates().then(function(response){
ctrl.dropdowns.air_dates = response.data;
console.log(response.data);
ctrl.pageDone = true;
});
};
init();
}
angular.module('command-center-app').controller('ReportsController', ReportsController);
I tried this, I looped through the array and made a new array containing only "syscode". That array I assigned it ctrl.selections.syscode which is the model. This should be the correct answer
ctrl.selectAll = function(){
var newitems = [];
angular.forEach(ctrl.dropdowns.syscodes, function(syscode) {
ctrl.selections.checked = 1;
newitems.push(syscode.syscode);
});
ctrl.selections.syscode = newitems;
}
There is something wrong with your implementation i think. The library uses an array to handle the checked values in it. But i don't think you are doing that. Plus ng-checked should be there. So:
<li ng-repeat="value in rc.dropdowns.syscodes">
<input type="checkbox" checklist-model="rc.selections.checked" checklist-value="value.syscode" />
{{value.readable_name}}
</li>
In the controller:
// Select All Logic
ctrl.selectAll = function(){
ctrl.selections.checked = [];
angular.forEach(ctrl.dropdowns.syscodeArray, function(user) {
ctrl.selections.checked.push( //iterate over all syscodes and push here
});
}
// Unselect All
ctrl.unselectAll = function(){
ctrl.selections.checked = [];
}
Let me know how it goes.

Angular copy doesn't keep client up to date

I'm creating a simple add post and comments app with https://thinkster.io/tutorials/mean-stack/wiring-everything-up. After finishing this section I should be able to add a post or comment and it save to the database and bind on the client side at the same time to keep the information current. However, it is only posting to the back end correctly and is not populating the post or comments array with the ng-model data. I believe the problem may be with the angular copy in the post service but do not see an error. The only difference I can see in my code and the tutorial is that it wanted to use .success for the callback of $http which I think is deprecated so I use .then instead. Below I will post the service, control, and ng-template, if you would like more information I can send a link to the repository.
Edit:Also I should note I know that it is working in the back end because I can see it in the collection or I can also manually refresh the browser and the new post is there. But obviously I shouldn't need to do a refresh.
Service
app.factory('posts', ['$http', function($http){
var o = {
posts:[]
}
o.get = function(id){
return $http.get('/posts/' + id).then(function(res){
return res.data;
});
};
o.getAll = function() {
return $http.get('/posts').then(function(data){
angular.copy(data.data, o.posts);
});
};
o.create = function(post) {
return $http.post('/posts', post).then(function(data){
o.posts.push(data);
});
};
o.upvote = function(post){
return $http.put('/posts/'+ post._id + '/upvote').then(function(data){
post.upvotes +=1;
});
}
o.addComment = function(id, comment){
return $http.post('/posts/' + id + '/comments', comment);
};
o.upvoteComment = function(post, comment){
return $http.put('/posts/' + post._id + '/comments/' + comment._id + '/upvote')
.then(function(data){
comment.upvotes += 1;
});
};
return o;
}])
Controller
app.controller('MainCtrl', ['$scope', 'posts', function($scope, posts){
$scope.test = 'Hello world!';
$scope.posts = posts.posts;
$scope.addPost = function(){
if(!$scope.title || $scope.title === '') { return; }
posts.create({
title: $scope.title,
link: $scope.link
});
$scope.title='';
$scope.link='';
}
$scope.incrementUpvotes = function(post) {
posts.upvote(post)
};
}]);
ng-template
<script type='text/ng-template' id='/home.html'>
<div class='page-header'>
<h1>Rawle News App</h1>
</div><!--End of page-header-->
<div ng-repeat='post in posts | orderBy: "-upvotes"'>
<span class="glyphicon glyphicon-thumbs-up"
ng-click="incrementUpvotes(post)"></span>
{{post.upvotes}}
<span class='link-titles'>
<a ng-show="post.link" href="{{post.link}}">
{{post.title}}
</a>
<span ng-hide="post.link">
{{post.title}}
</span>
<span>
Comments
</span>
</span>
</div>
<form class='post-form' ng-submit='addPost()'>
<div class='form-group'>
<input type='text' placeholder='title' ng-model='title'></input>
</div><!--End of form-group-->
<div class='form-group'>
<input type='text' placeholder='link' ng-model='link'></input>
</div><!--End of form-group-->
<button class='btn btn-primary' type='submit'>Post</button>
</form>
</script>
The post.create function is erroneous:
//ERRONEOUS
/*
o.create = function(post) {
return $http.post('/posts', post).then(function(data){
o.posts.push(data);
});
};
*/
//PUSH response.data
o.create = function(post) {
return $http.post('/posts', post).then(function(response){
o.posts.push(response.data);
//return value for chaining
return response.data
});
};
Try this in your controller.
$scope.addPost = function(){
if(!$scope.title || $scope.title === '') { return; }
posts.create({
title: $scope.title,
link: $scope.link
}).then(function(){
$scope.posts=posts.getAll();
});
Can you try this too please try this BEFORE:
$scope.addPost = function(){
if(!$scope.title || $scope.title === '') { return; }
posts.create({
title: $scope.title,
link: $scope.link
}).then(function(){
$scope.$apply();
});
o.getAll = function() {
return $http.get('/posts').then(function(data){
angular.copy(data.data, o.posts);
});
};
The above won't work as you're not returning anything from the then() statement.
o.getAll = function() {
return $http.get('/posts').then(function(data){
return angular.copy(data.data, o.posts);
});
};
Should get you closer.
Keep in mind that anytime you're in async land (returning promises etc) you need to handle it correctly in your controller/service/directive/whatever.
Side question, why are you still using $scope as opposed to controller instance as? This pattern has long been out of favor. Version of Angular?

Wait till images are loaded inside angularjs factory

I've created a small feature alowing users to search for movie titles. This does a JSON requests from tmdb.org which returns things like titles, dates and url's posters.
The controller:
angular.module('movieSeat')
.factory('moviesearchFactory', ['$http', '$q', '$rootScope', function ($http, $q, $rootScope) {
var factory = {};
function httpPromise(url) {
var deferred = $q.defer();
$http({
method: 'JSONP',
url: url
})
.success(function (data) {
deferred.resolve(data.results);
})
.error(function () {
deferred.reject();
});
return deferred.promise;
}
factory.getMovies = function (searchquery) {
return httpPromise('http://api.themoviedb.org/3/' + 'search/movie?api_key=a8f7039633f2065942cd8a28d7cadad4' + '&query=' + encodeURIComponent(searchquery) + '&callback=JSON_CALLBACK')
}
return factory;
}]);
The factory:
angular.module('movieSeat')
.controller('moviesearchCtrl', ['$scope', 'moviesearchFactory', function ($scope, moviesearchFactory) {
$scope.createList = function (searchquery) {
$scope.loading = true;
moviesearchFactory.getMovies(searchquery)
.then(function (response) {
$scope.movies = response;
})
.finally(function () {
$scope.loading = false;
});
}
}]);
The template:
<div ng-controller="moviesearchCtrl" id="movieSearch">
<div class="spinner" ng-show="loading">Loading</div>
<input ng-model="searchquery" ng-change="createList(searchquery)" ng-model-options="{ debounce: 500 }" />
{{ search }}
<ul>
<li ng-if="movie.poster_path" ng-repeat="movie in movies | orderBy:'-release_date'">
<span class="title">{{ movie.title }}</span>
<span class="release_date">{{ movie.release_date }}</span>
<img ng-src="https://image.tmdb.org/t/p/w300_and_h450_bestv2/{{ movie.poster_path }}" class="poster"/>
</li>
</ul>
</div>
The problem with this feature is that the spinner class only waits for the requested data. But just loading some JSON doesn't take long, it's downloading the images from the api in the browser that takes a while.
This causes 2 things. First of the spinner is removed before the images are rendered in the browser and because the images are all loaded async it causes a waterfall effect.
The easiest way to resolve this problem would to delay the .then call in the controller until the images are downloaded for the user and then go into the .finally call.
But I can't find a way to create something like that. Any tips?
Try this and let me know:
The idea is to use a directive to emit a render finished event:
dashboard.directive('onFinishRender', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit(attr.onFinishRender);
});
}
}
}
});
In the controller keep the event listener that wait for the image load promises:
$scope.$on('dataLoaded', function(ngRepeatFinishedEvent) {
// your code to check whether images has loaded
var promises = [];
var imageList = $('#my_tenants img');
for(var i = 0; i < imageList.length; i++) {
promises.push(imageList[i].on('load', function() {}););
}
$q.all(promises).then(function(){
// all images finished loading now
$scope.loading = false;
});
});
and in the html side:
<div id = "my_tenants">
<div ng-repeat="tenant in tenants" on-finish-render="dataLoaded">
// more divs
</div>
</div>

Categories

Resources