How to manage angularJS priority in Functions execution? - javascript

#Context
$scope.getAllEvents() is getting an array from Firebase database within the 10 last events and put it in the $scope.events array. Then the function is sorting by date $scope.events. I'm initializing $scope.spliceTab and calling $scope.spliceFunc().
$scope.counterPub() is triggered in HTML each time the ng-repeat $index is a multiple of 5. The function is storing in $scope.spliceTab each values of the $index which were triggered. Basically it's a tab where future new items locations are registered. Then i delete doubles and save results in $scope.result.
Finally, $scope.spliceFunc() is reading inside $scope.result, and insert into $scope.events new items where positions are stored into $scope.result.
#Running
At the start of my app, $scope.events is filled up but $scope.result from $scope.spliceFunc() stays empty. When I'm using the infinite scroll to load 10 more events, it is working but the $scope.events.sort() algorithm is working before $scope.spliceFunc(), so my new items are on the bottom of my list and not in the positions I want.
#Problem
I would like to run my app this way:
filled up $scope.events from Firebase
Sort $scope.events by date
ng-repeat in HTML and filled up $scope.spliceTab when triggered
Finally running $scope.spliceFunc() on the already sorted array $scope.events
What do you think, is this possible ?
// FUNCTION TO GET EVENTS
$scope.getAllEvents = function() {
if ($scope.listSiz === undefined) {
$scope.listSiz = 10;
}
var ref = firebase.database().ref().child("events");
$scope.events = $firebaseArray(ref.orderByChild('endDate').limitToFirst($scope.listSiz));
$scope.events.$loaded().then(function()
{
$scope.events.sort(function compareNumbers(y, x) {
var date1 = new Date(x.endDate);
var date2 = new Date(y.endDate);
return date1 - date2;
});
if ($scope.listSiz === 30) {
$scope.noMoreItemsAvailable = true;
}
$scope.spliceTab = [];
$scope.spliceFunc();
});
};
// FUNCTION TRIGGERED IN HTML
$scope.counterPub = function($index) {
var modulo = $index % 5;
if (modulo === 0) {
$scope.spliceTab.push($index);
// Delete doubles
$scope.result = [];
$scope.spliceTab.forEach(function(item) {
if ($scope.result.indexOf(item) < 0) {
$scope.result.push(item);
}
});
return true;
} else {
return false;
}
};
// FUNCTION SPLICE
$scope.spliceFunc = function() {
// console.log("************* TAB ****************** =", $scope.result);
angular.forEach($scope.result, function(value) {
$scope.events.splice(value, 0, [{
name: "toto"
}]);
});
};
<ion-view>
<ion-content>
<ion-list ng-controller="MCtrl">
<ion-item ng-repeat="e in events">
<!-- IF ADDS -->
<div ng-if="counterPub($index) === true">
Hello world !
</div>
<!-- -->
<div>
<img data-ng-src="{{ ::e.creatorAvatar }}">
</div>
</ion-item>
</ion-list>
</ion-content>
</ion-view>

Related

AngularJS select items not resetting to first / default value

I'm at my wits end! In angular I've got a controller and a view.
There are 2 dropdowns on the page which need to reset to default once the restart button has been clicked.
I can set the value of the boxes as they render by pushing a "select" option into the collection inside the controller. However, when the reset button is pressed, which runs the init() method again, the dropdowns should be set back to the first value. This doesn't occur, the values for $scope.selectedYear and $scope.selectedReport remain as they did before the reset button was pressed.
This is the full code for the controller
function TreeReportsCHLController($scope, $q, $routeParams, reportsDashboardResource, navigationService, notificationsService, dialogService, entriesManageDashboardResource, $timeout) {
// Methods
var generalError = function () {
notificationsService.error("Ooops", "There was an error fetching the data");
$scope.actionInProgress = false;
}
// Scope
$scope.selectedYear = "";
$scope.init = function () {
$scope.hasCompleted = false;
$scope.actionInProgress = false;
$scope.yearSelected = false;
$scope.reportTypes = ["Choose", "Entered", "ShortListed", "Winner", "Recieved"];
$scope.selectedReport = "";
$scope.entryYears = new Array();
$scope.entryYears.push("Choose a Year");
entriesManageDashboardResource.getEntryYears().then(function (response) {
angular.forEach(response, function (value, key) {
$scope.entryYears.push(value);
});
});
$scope.selectedYear = $scope.entryYears[0];
$scope.selectedReport = $scope.reportTypes[0];
};
$scope.yearHasSelected = function(selectedYear) {
$scope.yearSelected = true;
$scope.selectedYear = selectedYear;
};
$scope.generateFile = function (selectedReport) {
$scope.actionInProgress = true;
var reportDetail = {
entryYear: $scope.selectedYear,
chosenEntryStatus: selectedReport
};
reportsDashboardResource.generateEntriesReportDownloadLink(reportDetail).then(function (response) {
if (response.Successful) {
$scope.hasCompleted = true;
} else {
notificationsService.error("Ooops", response.ErrorMessage);
}
$scope.actionInProgress = false;
}, generalError);
};
$scope.restart = function () {
$scope.init();
}
// Initialise Page
$scope.init();
}
angular.module("umbraco").controller("ReportsDashboardController", TreeReportsCHLController)
this is the code with the dropdowns in it;
<table>
<tr>
<td>Get a report for year: {{selectedYear}}</td>
<td><select ng-model="selectedYear" ng-change="yearHasSelected(selectedYear)" ng-options="year for year in entryYears" no-dirty-check></select></td>
</tr>
<tr ng-show="!hasCompleted && yearSelected">
<td>
Get Report Type:
</td>
<td>
<select ng-model="selectedReport" ng-change="generateFile(selectedReport)" ng-options="status for status in reportTypes" no-dirty-check ng-disabled="actionInProgress"></select>
</td>
</tr>
</table>
I've also done a further test where I simply set $scope.selectedYear to $scope.entryYears[0] within the reset method. When I console.log $scope.selectedYear here, the value confirms it has been changed, but strangely where I've outputted the $scope.selectedYear / {{selectedYear}} to the page for testing, this does not update. It's almost as though the binding between the controller and the view isn't occuring.
Any help?
Thank-you.
Here's a working plunk that is somewhat stripped down since I didn't have access to of the services that your are injecting into your controller. The changes I made in the controller are:
First,
$scope.entryYears = new Array();
becomes
$scope.entryYears = [];
as this is the preferred way to declare an array in js.
Second, I removed $scope.apply() that was wrapping
$scope.selectedYear = $scope.entryYears[0];
$scope.selectedReport = $scope.reportTypes[0];
as this was causing infinite digest cycles.

Navigate limitTo batches in Angular ngRepeat

I have an ngRepeat with a limitTo in my HTML. This will show the first x number of users - essentially paginating the table. I now need to be able to show the next batch of x users. I've added a couple of anchors to go to previous or next page (with functions attached to the click)
I'm now not sure how to manipulate the ngRepeat through these functions to actually show the correct batch of users.
HTML
<div ng-repeat="user in users | limitTo:paginate.size">
{{user.name}}
{{user.email}}
</div>
<ul class="pagination">
<li>left</li>
<li>right</li>
</ul>
JS
$scope.users = //full users object here
$scope.paginate = {};
$scope.paginate.size = 10;
$scope.prevPage = function(){
//load the previous 10 users
}
$scope.nextPage = function(){
//load the next 10 users
}
You should add another filter (or simply a custom filter) such as
<div ng-repeat="user in users | filter:getList(user, index)">
{{user.name}}
{{user.email}}
</div>
and then in the scope
$scope.users = //full users object here
$scope.paginate = {};
$scope.paginate.size = 10;
$scope.paginate.start = 0;
$scope.prevPage = function(){
//load the previous 10 users
if ($scope.paginate.start) {
$scope.paginate.start -= $scope.paginate.size;
}
}
$scope.nextPage = function(){
//load the next 10 users
$scope.paginate.start += $scope.paginate.size;
}
$scope.getList = function (user, index) {
return (index >= $scope.paginate.start && index < $scope.paginate.start + $scope.paginate.size);
};

Angular js function logic and repetition error

I'm having a logic error with my code using angular js. What I have done is made a function that loops through a json array and returns the strings of the weather condition, eg
'clear',
'cloudy', etc...
It then checks to see if the value of the string is equal to another string. If it is, it returns an image link associated with the weather condition. The problem is that html ng-repeat function is repeating that one image and not any other image.
Here is the js:
var app=angular.module('app');
app.controller('MainCtrl', function($scope, $http) {
$scope.currentSydney = null;
$scope.currentMelbourne = null;
$scope.currentAdelaide = null;
$scope.currentDarwin = null;
$scope.currentBrisbane = null;
$scope.currentMelbourne = null;
$scope.currentCairns = null;
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Melbourne.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentMelbourne=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Sydney.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentSydney=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Adelaide.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentAdelaide=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Darwin.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentDarwin=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Perth.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentPerth=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Cairns.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentCairns=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Brisbane.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentBrisbane=data;
$scope.cityData=[
{ name:'Brisbane',
temp:$scope.currentBrisbane.current_observation.temp_c,
image:$scope.currentBrisbane.current_observation.icon
},
{ name:'Melbourne',
temp:$scope.currentMelbourne.current_observation.temp_c,
image:$scope.currentMelbourne.current_observation.icon
},
{
name:'Adelaide',
temp:$scope.currentAdelaide.current_observation.temp_c ,
image:$scope.currentAdelaide.current_observation.icon
},
{ name:'Darwin',
temp:$scope.currentDarwin.current_observation.temp_c ,
image:$scope.currentDarwin.current_observation.icon
},
{ name:'Perth',
temp:$scope.currentPerth.current_observation.temp_c ,
image:$scope.currentPerth.current_observation.icon
},
{ name:'Cairns',
temp:$scope.currentCairns.current_observation.temp_c,
image:$scope.currentCairns.current_observation.icon
},
]
for(y = 0 ; y < 6; y++){
var string = $scope.cityData[y].image;
console.log(string[10]);
}
});
$scope.iconString = function() {
switch ($scope.currentSydney.current_observation.icon) {
case 'partlycloudy' :
return 'pics/partlycloudy.png';
case 'clear' :
return 'pics/partlycloudy.png';
}
}
$scope.repeat = function() {
for(y = 0 ; y < 1; y++){
var string = $scope.cityData[y].image;
if(string=='mostlycloudy'){
return 'pics/mostlycloudy.png';
}
}
}
});
And here is the html:
<div id="weather-container">
<div id="current-weather">
<!--Angular JSON pull -->
<div id="title"><span id="current-title">Current Weather</span></div>
<div id="current-condition">{{currentSydney.current_observation.weather}}</div>
<img ng-src="{{iconString()}}"></img>
<div id="current-temp"><span id="current-temp"> {{currentSydney.current_observation.temp_c}} </span></div>
<span id="current-city">{{currentSydney.current_observation.display_location.city}} </span>
</div>
<!--Angular JSON pull and iteration-->
<div id="other-city-container">
<div class="other-city-weather" ng-repeat="city in cityData" >
<!--Image-->
<img ng-src="{{repeat()}}"></img>
<div class="current-city-temp">
<span>{{city.temp}}</span>
</div>
<div class="current-city-lower">
<span>{{city.name}}</span>
</div>
</div>
</div>
</div>
Now I'm calling the repeat function in the html inside the img src tag.
`
I see. You are making 2 loops : ng-repeat in the view, and a for loop in the controller ( repeat() ).
But I think that right now, they are not related to each other (which is what you need I guess): getting the index of the ng-repeat loop in your repeat method.
Try something like that :
In the view :
<img ng-src="{{repeat($index)}}" /><!-- Getting the current $index of the ng-repeat loop and passing it to the $scope.repeat() method -->
In the controller :
$scope.repeat = function(index) { // there, index becomes the value we just put in the view ($index = the current index of the ng-repeat loop), e.g. : 0,1,2,3...
var string = $scope.cityData[index].image; // We go get the right city in the cityData array, according to the current ng-repeat index.
// then we do the job
if(string=='mostlycloudy'){
return 'pics/mostlycloudy.png';
}
}
Not sure that works as I didn't test it, but you may know what I mean ?

When I keep refreshing my angularJS page, the content sometimes shows up, sometimes doesn't

I have a page running angularJS. Sometimes, when I open the document, the data that needs to appear only sometimes shows up. When I keep trying to refresh the page, it's pretty much random: sometimes the content appears, sometimes it doesn't.
The section of the code that runs this looks like this:
<div class="row">
<div class="col-md-12" ng-repeat="(observer,hosts2) in bugDuration">
{{observer}}
<div class="row">
<div class="col-md-3" ng-repeat="(host, bugs2) in hosts2"> {{host}}
<div ng-repeat="(bug, duration) in bugs2">
{{bug}} for {{duration}} seconds.
</div>
</div>
</div>
</div>
</div>
As you can see, it is using ng-repeat, and my best guess is that when this code is running, the ng-repeat objects, such as bugDuration are empty, so none of it runs.
My script that initializes all of these variables is located after, in my document. Is there something I should do in the controller or whatever so the variables can be refreshed and the content can be shown everytime?
Edit
Here is the code where bugDuration is initialized:
bugDuration = {};
bugTracker = {};
$.getJSON('../java_output/bugs.json', function (data) {
for ( var observer in data ) {
bugDuration[observer] = {};
for (var host in data[observer]) {
bugDuration[observer][host] = {};
for (var bug in data[observer][host]) {
bugDuration[observer][host][bug] = data[observer][host][bug].duration;
}
}
}
console.log (bugDuration);
});
$.getJSON('../java_output/bug_summary.json', function (data) {
var numObservers = data.numObservers;
delete data['numObservers'];
JSONbugsList = data;
var bugTracker = {};
for (var observer = 1; observer <= numObservers; observer++) {
observers.push(observer);
observerKeys = Object.keys(data);
// observerKeys.splice(observerKeys.indexOf('numObservers'));
for (var host in data["observer" + observer]) {
if (hosts.indexOf(host) == -1) {
hosts.push(host);
}
hostKeys = Object.keys(data["observer" + observer]);
for (var bug in data["observer" + observer][host]) {
if (bugs.indexOf(bug) == -1) {
bugs.push(bug);
}
for (var i in data["observer" + observer][host][bug]) {
bugTracker[bug] = true;
var dateVar = data["observer" + observer][host][bug][i];
var intoList = {"observer":observer, "host":host, "bug":bug, "start":(new Date(1000*dateVar.start)), "end":(dateVar.end==null?' the end.':(new Date(1000*dateVar.end)))}
}
}
}
}
// Removed unimportant stuff here//
$scope.$apply();
$scope.hostsS = hosts;
$scope.bugsS = bugs;
$scope.observersS = observers;
$scope.JSONbugsList = JSONbugsList;
$scope.hostKeys = hostKeys;
$scope.observerKeys = observerKeys;
$scope.start = 'start';
$scope.end = 'end';
$scope.bugDuration = bugDuration;
$scope.$apply();
The biggest problem among others is that $scope.$apply() needs to happen after the data gets set on the $scope. Since $.getJSON is asynchronous, by the time the callback gets triggered, the $scope.$apply() lines at the bottom will have already been fired.
$.getJSON('../java_output/bug_summary.json', function (data) {
/*do stuff outside of angular context when the ASYNC callback fires*/
$scope.stuff = data;
/*then call $scope.$apply()*/
$scope.$apply();
});

AngularJS: Hitting a strange issue with $scope variables

In the following code, whenever you delete an item from the delete link in the list, it will only delete the item from the list, but it will not delete the currently selected item. (The item displaying once you click on it). However, if you click on the delete link next to the currently selected item, it will delete from both places.
To replicate what I'm seeing:
Add a bunch of items by typing in the text box and hitting enter a few times.
Select one of the items from the list.
Click delete next to the item when it displays below.
This is the correct behavior.
Select another item you created earlier.
Now click the delete link next to the item in the list.
The item is removed from the list, but not the currently displayed item.
When I step into the code $scope.currentUser is undefined when I click on the delete link in the list.
Why is this happening?
<html ng-app="myApp">
<head>
<script src="http://code.angularjs.org/1.0.1/angular-1.0.1.min.js"></script>
<script>
var app = angular.module('myApp', []);
app.config(function($routeProvider) {
$routeProvider.when('/User/:id', {
controller: UserCtrl,
template: '<h1>{{currentUser.name}}</h1> <a ng-click="deleteUser(currentUser.id)">delete me</a>'
});
});
app.factory('userSvc', function(){
return new UserService();
});
function UserCtrl($scope, $routeParams, $location, userSvc) {
var currUser = userSvc.getUser($routeParams.id);
$scope.currentUser = currUser;
$scope.users = userSvc.getAllUsers();
$scope.addUser = function () {
var user = {
id: userSvc.nextId(),
name: $scope.addUserName
};
userSvc.addUser(user);
$scope.addUserName = '';
$location.url('/User/' + user.id);
};
$scope.deleteUser = function(id) {
if($scope.currentUser != null && $scope.currentUser.id == id) {
$scope.currentUser = null;
}
userSvc.delete(id);
};
};
function UserService() {
var users = [{id: 1, name: 'Ben' }];
this.delete = function(id) {
for(var i = 0; i < users.length; i++) {
var user = users[i];
if(user.id == id) {
users.splice(i,1);
}
}
};
this.addUser = function(user) {
users.push(user);
};
this.getAllUsers = function() {
return users;
};
this.getUser = function(id) {
for(var i = 0; i < users.length; i++) {
var user = users[i];
if(user.id == id) {
return user;
}
}
};
this.nextId = function() {
var maxId = 0;
for(var i = 0; i < users.length; i++) {
var user = users[i];
maxId = Math.max(maxId, user.id);
};
return maxId + 1;
};
}
</script>
</head>
<body>
<div ng-controller="UserCtrl">
<form ng-submit="addUser()">
<input ng-model="addUserName" type="text"/>
<input type="submit" value="Add"/>
</form>
<ul>
<li ng-repeat="user in users">{{user.name}} <a ng-click="deleteUser(user.id)">delete</a></li>
</ul>
</div>
<div ng-view></div>
</body>
</html>
It turns out that selecting a user from the list actually also created a brand new scope that was seperate from the one used to bind the list.
Thanks to Gloopy's comment above to check out Batarang, I was able to see this happen. If this happens to help you, please +1 his comment.
According to the documentation on Scopes some directives will actually cause a new scope to be created. I'm assuming that clicking a link that is being handled by the $routeProvider also results in the creation of a whole new scope tree, likely because it's creating another instance of that controllor.

Categories

Resources