I'm using angular's ng-repeat to populate table with data from GitHub api and I want one of the <td> to execute method that will return data. the problem is that this makes the function execute infinitely.
HTML:
<table>
<thead>
<tr>
<th>Name</th>
<th>Languages</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="repo in repos">
<td>{{repo.name}}</td>
<td></td> <!-- Get languages for each repo here. -->
</tr>
</tbody>
</table>
Angular:
(function(){
var app = angular.module("githubViewer", []);
var MainController = function($scope, $http){
var onUserComplete = function(response){
$scope.user = response.data;
$http.get($scope.user.repos_url)
.then(onRepoComplete, onError);
};
var onRepoComplete = function(response){
$scope.repos = response.data;
};
var onError = function(reson){
$scope.error = "Could not fetch the data";
};
//search for user
$scope.search = function(username){
$http.get("https://api.github.com/users/" + username)
.then(onUserComplete, onError);
};
// These two execute infinately if executed in the ng-repeat's <td>
$scope.findLangs = function(langsUrl){
$http.get(langsUrl)
.then(onLangComplete, onError);
}
var onLangComplete = function(response){
return response.data;
};
};
app.controller("MainController", ["$scope", "$http", MainController]);
})();
I've tried using {{ findLangs(repo.languages_url) }} in the <td> but it causes me to get this error:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
and appears to be infinitely executing.
I don't think you can use an expression there because you don't actually return a value from the findLangs() function. That said, I don't think that would cause an infinite loop. I think you'll need to actually grab the language data for each repo within the onRepoComplete callback, then just use that data in your template:
var onRepoComplete = function(response){
$scope.repos = response.data;
$scope.repos.forEach(function(repo) {
$http.get(repo.languages_url)
.then(function(response) {
// change this to process the language data however you need to...
repo.languages = JSON.stringify(response.data);
},onError);
});
};
Then in your template you can use the languages property of the repo:
<tr ng-repeat="repo in repos">
<td>{{repo.name}}</td>
<td>{{repo.languages}}</td>
</tr>
Related
I have trouble with calling a function when the page loads. I'm not sure what tag I should use within html to run Angular application.
I am trying to pull user data from a database and display it in a table. It works when I use a button to call the function but I would like it to be more automated. I've done some research and it always leads me to using the controller but I am sure there has to be a simpler solution.
<tbody>
<Button ng-click="fetchEveryone();">click</Button>
<tr ng-repeat="user in all_users">
<td>
<img src="/images/{{user.pic}}" style="height: 50px; width: 50px; border-radius: 100px;"/>
</td>
<td>{{user.name}}</td>
<td>{{user.email}}</td>
<td>
<select ng-change="" ng-model="selectedMeeting">
<option value="">Select Meeting Type...</option>
<option ng-repeat="meeting in meetings">{{meeting}}</option>
</select>
</td>
<td>
<button>request</button>
</td>
</tr>
</tbody>
Here is the Angular code. It makes a request to python server.
$scope.fetchEveryone = function(){
var req = {
verb: 'getPeople',
names: $scope.Allusers
}
$scope.callAPI(req, function(response){
$scope.all_users = response;
$scope.view = 'viewPerson'
});
}
You can call it using ng-init as haakon319 suggested in this post. Otherwise, you can call it in your controller after the function definition and it will run when the controller loads:
function myController($scope){
$scope.callAPI = function(req, callback){
//some function
};
$scope.fetchEveryone = function(){
var req = {
verb: 'getPeople',
names: $scope.Allusers
}
$scope.callAPI(req, function(response){
$scope.all_users = response;
$scope.view = 'viewPerson'
});
};
$scope.fetchEveryone();
}
If you have more than one thing that needs to happen, better practice might be to have a dedicated init function to call all needed functions:
function myController($scope){
$scope.callAPI = function(req, callback){
//some function
};
$scope.fetchEveryone = function(){
var req = {
verb: 'getPeople',
names: $scope.Allusers
}
$scope.callAPI(req, function(response){
$scope.all_users = response;
$scope.view = 'viewPerson'
});
};
function moreBackendCalls(){
//more backend calls
};
function init(){
$scope.fetchEveryone();
moreBackendCalls();
//init some variables
$scope.test1 = 'new test';
$scope.test2 = 73;
}
init();
}
Alternatively, you can add the init to scope with:
$scope.init = function(){
.....
}
and add to your HTML in the following way:
<tbody ng-init="init()">
.......
</tbody>
It will then run when the route with that html is loaded.
I'm using AngularJS in a Firebase app and I have a function where I do some inner join to get some data. More details here. After getting the response from the firebase api I create an object and push it into an array (a scope variable). I see in the debug that the data has been retrieved and that the $scope variable is filled correctly. The problem is that it is not showing in the ng-repeat.
My function:
$scope.getMessagesByRegion = function(regionId){
console.log('Function start');
var rootRef = firebase.database().ref();
var regionMessagesRef = rootRef.child("region_messages/"+ regionId);
$scope.messages_by_region = []; // Here I reset the scope variable
regionMessagesRef.on('child_added', function(rmSnap) {
var messageRef = rootRef.child("messages/"+rmSnap.key);
messageRef.once('value').then(function(msgSnap){
var msg = {
key : msgSnap.key,
name : msgSnap.val().name,
type : $scope.getTypeName(msgSnap.val().type),
show_only_once : rmSnap.val().show_only_once,
pre_requisite_message : rmSnap.val().pre_requisite_message
}
console.log(msg); // here I see the object in the console. it is OK
$scope.messages_by_region.push(msg); // pushing the item
console.log('----------------');
console.log($scope.messages_by_region);
})
});
}
My HTML:
<table class="table">
<thead>
<tr>
<th>Message name</th>
<th>Type</th>
<th>Show only once</th>
<th>Pre requisite</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="msg in messages_by_region">
<td ng-bind="msg.name"></td>
<td ng-bind="msg.type"></td>
<td ng-bind="msg.show_only_once"></td>
<td ng-bind="msg.pre_requisite_message"></td>
</tr>
</tbody>
</table>
This is what I see in the console:
The problem is that even having an object in the array it is not shown in the view. It is like there was an empty array set to the $scope.messages_by_region variable
I'm having a hard time figuring out what I'm doing wrong. Can you see what's wrong with my function?
Thanks for any help.
try,
$scope.$apply(function(){
$scope.messages_by_region.push(msg);
});
or,
$scope.messages_by_region.push(msg);
$scope.$apply();
Since you're using async functions (Cosuming of firebase API) you should tell angular to refresh the HTML;
Use
$scope.$diggest()
More information you can find on https://www.sitepoint.com/understanding-angulars-apply-digest/
As you are performing Async calls you need to tell angular to refresh the changes in the value with $apply call you can do it with:
$scope.getMessagesByRegion = function(regionId) {
console.log('Function start');
var rootRef = firebase.database().ref();
var regionMessagesRef = rootRef.child("region_messages/" + regionId);
$scope.messages_by_region = []; // Here I reset the scope variable
regionMessagesRef.on('child_added', function(rmSnap) {
var messageRef = rootRef.child("messages/" + rmSnap.key);
messageRef.once('value').then(function(msgSnap) {
var msg = {
key: msgSnap.key,
name: msgSnap.val().name,
type: $scope.getTypeName(msgSnap.val().type),
show_only_once: rmSnap.val().show_only_once,
pre_requisite_message: rmSnap.val().pre_requisite_message
}
$scope.$apply(function() {
console.log(msg); // here I see the object in the console. it is OK
$scope.messages_by_region.push(msg); // pushing the item
console.log('----------------');
console.log($scope.messages_by_region);
});
});
});
}
For more information on this behavior you can also read article describing the problem here
Very new to Angularjs. So I have some JSON files that I am reading into my webpage that contain and array of objects that are cars. What I am trying to do is have my "button" when pressed alert me to the data specific to that button.
The ng-repeat is running 8 times so that is the length of the array, but in angularJs i'm not sure how to basically store the array index for each time the ng-repeat passes in my button function.
This is my a snippet of my .html:
<div class="carTable table-responsive text-center" ng-controller="ButtonController" >
<table class="table specTable">
<thead>
<tr>
<th>Make</th>
<th>Model</th>
<th>Year</th>
<th>Color</th>
<th>Milage</th>
<th>Doors</th>
<th class="reserve">Horsepower</th>
<th>Price</th>
<th class="reserve"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="cars in car | orderBy:'year'">
<td>{{cars.year}}</td>
<td>{{cars.model}}</td>
<td>{{cars.make}}</td>
<td>{{cars.color}}</td>
<td>{{cars.mileage | number}}</td>
<td>{{cars.doors}}</td>
<td>{{cars.horsepower}}</td>
<td>{{cars.price | number}}</td>
<td><div class="panel panel-default">Reserve</div></td>
</tr>
</tbody>
</table>
</div>
The portion in question is at the bottom where I have a Reserve "button"
I'm leaving out my JSON files, works properly there. I'm just not sure how to keep track of the array index as the ng-repeat does its thing.
Here is the angular:
(function(){
var app = angular.module("myReserveApp", []);
app.controller("ButtonController", ["$scope", "$window", function($scope, $window){
$scope.buttonPress = function(){
$window.alert(JSON.stringify($scope.car[0]));
}
}]);
var MainController = function($scope, $http, $window){
var onGatherBoatData = function(response){
$scope.boat = response.data;
};
var onError = function(reason){
$scope.error = "Could not fetch Boat Data";
};
var onGatherCarData = function(response){
$scope.car = response.data;
};
var onError = function(reason){
$scope.error = "Could not fetch Car Data";
};
var onGatherTruckData = function(response){
$scope.truck = response.data;
};
var onError = function(reason){
$scope.error = "Could not fetch Truck Data";
};
$scope.message = "Hello, Angular Here!";
};
app.controller("MainController", ["$scope", "$http", "$window", MainController]);
}());
Currently in the top portion of the code I just have it alerting object[0] but I want it to be specific to which button is pressed. Any help is appreciated, thank you.
$index refers to the index in ng-repeat. So if you want to pass your function the index in array on the button click, change buttonPress() to buttonPress($index)
you'll have to change your controller to something like the following:
$scope.buttonPress = function(index){
$window.alert(JSON.stringify($scope.car[index]));
}
To do the following, you can just pass the current data in the ngRepeat. Moreover,if you want the current index, the ngRepeat directive provide specials properties, as the $index, which is an iterator.
$scope.buttonPress = function(car, index){
//Retrieve current data of the ngRepeat loop
console.log(car);
//Current index of your data into the array
console.log(index);
}
Then you can call your function like this :
Reserve
First, thank you both for the quick responses. Both of these answers work. I found another way to do it as well before reading your posts.
<div class="panel panel-default">
Reserve:{{car.indexOf(cars)}}
</div>
Using (car.indexOf(cars)) gives me the same result
$scope.buttonPress = function(index){
$window.alert(JSON.stringify(index));
}
Now when I click on the "button" it sends me back the array index, so now I should be able to play with that data. Thank you again both, for your help.
I am having some trouble setting some values for a widget I am making. I am using Ozone widget framework, but that part is negligible to this discussion. Here us the html where I am trying to set the variable (for now just focus on {{user.user}} part.
<div class="col-lg-12">
<p>User: {{user.user}}</p>
<table class="table table-bordered table-hover table-striped">
<thead>
<th>#</th>
<th>Model</th>
<th>Score</th>
<th>Date</th>
</thead>
<tr data-ng-repeat=" item in records | orderBy : '-score' | limitTo : 10 " ng-click="">
<td>{{$index+1}}</td>
<td>{{item.model}}</td>
<td>{{item.score}}</td>
<td>{{item.date}}</td>
</tr>
</table>
</div>
And here is the Angular / owf to go with it:
angular.module('myapp', ['cgOwf'])
.controller('MainCtrl', function($scope, $http, owf) {
var records;
$scope.selectPost = '';
$scope.searchText = '';
console.debug("before IT HERE!!!");
owf.ready(function(){
console.debug("MADE IT HERE!!!");
owf.Eventing.subscribe('user-status', function(sender, msg, channel) {
console.debug('[%s] - received message %o', channel, msg);
$scope.user = msg;
});
});
$scope.search = function() {
//clear the select, go here http://jsonplaceholder.typicode.com/comments
//and display/filter emails based on the search input
$scope.selectPost = "";
$scope.selectedItem = null;
$http.get('https://api.myjson.com/bins/1jvst').success(function(data2) {
$scope.records = [];
data2.forEach(function(r) {
if (r && r.user && r.user.toLowerCase().indexOf($scope.searchText.toLowerCase()) !== -1) {
$scope.records.push(r);
}
});
});
};
});
The part I am having trouble with is $scope.user = msg;. At that point in the code, msg is a JSON object, and I am sure of that because it checks out in the js debugger in chrome. AFAIK that is how I would set the object so I could access it in the html, though something clearly doesn't work.
The owf event probably isn't triggering a $digest cycle, so the view never updates. You can run $scope.apply() to force a $digest
owf.Eventing.subscribe('user-status', function(sender, msg, channel) {
console.debug('[%s] - received message %o', channel, msg);
$scope.$apply(function() {
$scope.user = msg;
});
});
I have this code:
$scope.search = function() {
$scope.results = ejs.Request()
.query(ejs.TermQuery("amount", 10)).size(10).from(0)
.doSearch();
console.log($scope.results.v);
};
and :
<tr id="tr" ng-repeat="record in results.hits.hits" repeat-done="reload_scroll()">
<td><input type="checkbox" ng-model="record._source.checked"/></td>
<td>{{ record._source.id }}</td>
</tr>
and it work properly. But I want to have access to $scope.results in js code but when I write:
$scope.search = function() {
$scope.results = ejs.Request()
.query(ejs.TermQuery("amount", 10)).size(10).from(0)
.doSearch();
console.log($scope.results.$$v);
};
but it print undefined it console, what should I use instead $$v?
Thanks.
Since it is a async call you would get the results in a callback. Something like
ejs.Request()
.query(ejs.TermQuery("amount", 10)).size(10).from(0)
.doSearch().then(function(data) {
console.log(data);
});