My directive with controller :
app.directive("photoGallery", function() {
return {
restrict: 'E',
templateUrl: 'part/photoGallery.html',
controller: ["$http", function($http) {
me = this;
this.autoSlide = true;
this.currentIndex = 2;
this.autoSlide_timer;
this.photos = [{}];
this.Show = function(index) {
me.currentIndex = index;
};
this.Next = function() {
me.currentIndex++;
console.log(me.currentIndex);
if (me.currentIndex >= me.photos.length) {
me.currentIndex = 0;
}
me.Show(me.currentIndex);
};
this.Prev = function() {
me.currentIndex--;
if (me.currentIndex < 0) {
me.currentIndex = me.photos.length-1;
}
me.Show(me.currentIndex);
};
this.Init = function() {
$http.get("img/slider/_data.json")
.success(function(data) {
me.photos = data;
for(var i in me.photos) {
me.photos[i].index = i;
}
console.info(me.photos);
})
.error(function(e){
console.error(e);
});
this.autoSlide_timer = setInterval(this.Next, 1500);
}();
}],
controllerAs: 'gallery'
};
});
photoGallery.html :
<div class="GalleryContainer">{{gallery.currentIndex}}
<div class="PhotoWrapper">
<div ng-repeat="photo in gallery.photos" class="photo" ng-class="{active:gallery.currentIndex == photo.index}">
<img ng-src="img/slider/{{photo.path}}">
</div>
</div>
</div>
as you can see, in the Next() function, I log currentIndex
Next() is called every 1500ms thanks to setInterval(this.Next, 1500) in the Init() function.
I can see in the console : 2, 3, 4, ... 10, 0, 1, 2 ...
But in the browser, {{gallery.currentIndex}} is never updated, it display the default value (2) (photoGallery.html line 1)
You have to use angular $interval() instead of JavaScript setInterval() function. Why ?
Because Angular needs to know when variables are updated. $interval make a call to $scope.$apply() at the end of its execution, executing a new $digest loop that notify the update to angular.
You can also wait the request to be successfully proceed to set you interval, to avoid errors.
this.Init = function() {
$http.get("img/slider/_data.json")
.success(function(data) {
me.photos = data;
for(var i in me.photos) {
me.photos[i].index = i;
}
console.info(me.photos);
me.autoSlide_timer = $interval(me.Next, 1500);
})
.error(function(e){
console.error(e);
});
}();
Related
I have an Event that is called when the document loads to make it able to click each element with the Class 'header' to expand and show more details:
$(document).ready(function () {
InitClick();
});
Here is the function:
function InitClick() {
$('.header').click(function () {
$(this).nextUntil('tr.header').slideToggle();
});
}
Now the issue is when the results get filtered, it will then cause that click event to stop until I re-initialise it, then it will start working again... Until the Data is filtered again or has to update.
Now my main question is, has anyone got a link to something that could assist me, I've tried putting is on a $watch but the main issue I keep having is that this is called before the filtered data is returned, causing it to initialise before the data is there.
Here is MyApp.js if it helps?
var MyApp = angular.module('MyApp', []);
MyApp.controller('MyAppCtrl', function ($scope, $filter) {
$scope.Users = tJSONData;
$scope.currentPage = 0;
$scope.pageSize = 3;
$scope.Pages = [];
$scope.search = '';
$scope.Completed = '';
$scope.getData = function () {
return $filter('filter')($scope.Users, $scope.search || $scope.Completed);
}
$scope.numberOfPages = function () {
return Math.ceil($scope.getData().length / $scope.pageSize);
}
$scope.$watch('numberOfPages()', function (newVal, oldVal) {
var tPages = [];
for (i = 0; i < $scope.numberOfPages(); i++) {
tPages.push(i + 1);
}
if ($scope.currentPage >= $scope.numberOfPages()) {
$scope.currentPage = $scope.numberOfPages() - 1;
}
if ($scope.currentPage == -1) {
$scope.currentPage = 0;
}
return $scope.Pages = tPages;
})
$scope.updatePage = function () {
$scope.$apply(function () {
$scope.Users = tJSONData
})
}
$scope.limitPagination = function () {
if ($scope.currentPage == 0) {
return $scope.currentPage;
} else if ($scope.currentPage == 1) {
return $scope.currentPage - 1
} else {
return $scope.currentPage - 2;
}
}
});
MyApp.filter('startFrom', function () {
return function (input, start) {
start =+ start; //parse to int
return input.slice(start);
}
});
Any help is appreciated :)
In a nutshell, when you call $(selector).click (or any other event), it will only set up the event for the elements that were grabbed at the time of the call. If the elements are removed and replaced (as seems to be your case), the new elements won't automatically have it.
Instead of using $(selector).click(callback), use $(document).on('click', selector, callback)
In your case, it looks like this should do the trick:
$(document).on('click', '.header', function () {
$(this).nextUntil('tr.header').slideToggle();
});
The difference is that this way, the event is actually bound to the document itself, which never changes. You then filter so it'll only trigger when you click a .header, but it'll apply to all of them, even those added after this bit is called.
Below directive is used for getting data continuously from server with default interval of 5 sec
app.directive('livestatDataGrid', livestatDataGrid);
function livestatDataGrid($http, $interval, $window) {
return {
restrict: 'E',
templateUrl: 'directives/livestatDataGrid/livestat-datagrid.html',
scope: {
viewName: '=viewName',
gridOptions: '=',
deleteItem: '=deleteItem'
},
link: function($scope) {
var defaultSec = 5;
$scope.timerObj = {};
$scope.timerObj.selectedItem = defaultSec;
$scope.timerObj.isDisplay = true;
var timer = null;
$scope.copyVal = defaultSec;
$scope.getViewData = function(viewName) {
console.log('Came here !! Directive ', viewName);
$http.get('json/' + viewName + '.json').then(function success(response) {
$scope.metricHeader = response.data.metricHeader;
$scope.stats = response.data.stats;
}, function error(error) {
console.log("Eooor ", error)
});
};
$scope.getViewData($scope.viewName);
// Timer code
$scope.editTimer = function() {
$scope.timerObj.isDisplay = false;
};
$scope.setTimer = function() {
if ($scope.timerObj.selectedItem && isNaN($scope.timerObj.selectedItem)) {
$scope.timerObj.selectedItem = defaultSec;
}
if ($scope.copyVal != "" && $scope.copyVal == $scope.timerObj.selectedItem) {
$scope.timerObj.isDisplay = true;
return;
}
$scope.StopTimer();
$scope.copyVal = angular.copy($scope.timerObj.selectedItem);
$scope.timerObj.isDisplay = true;
$scope.startTimer();
};
// starting the timer here once directive is initialized.Using `$interval`
$scope.startTimer = function() {
console.log("in timer " + $scope.timerObj.selectedItem);
if ($scope.timerObj.selectedItem && $scope.viewName) {
//time interval for sending request to server
timer = $interval(function() {
if ($scope.viewName)
$scope.getViewData($scope.viewName);
$interval.cancel(this);
console.log(timer)
}, $scope.timerObj.selectedItem * 1000);
}
};
$scope.startTimer();
// Once the job is done, destroy the timer using `$interval.cancel`.
$scope.StopTimer = function() {
if (angular.isDefined(timer)) {
console.log("in stop timer");
$interval.cancel(timer);
}
};
//timer code ends her
}
}
}
Not clear what do you intend to ask/discuss. Is this a self answer question?
I'm looking on how to make a 60 seconds countdown using angular js.
I want to show the countdown on the page ! and when the countdown is finished, the controller should reload to execute the code again ! and get the update json object !
my controller looks like :
.controller('todaymatches', function($rootScope,$scope, $http) {
$http.get("http://www.domaine.com/updatedjson/")
.success(function (response) {
$scope.matches = response;
});
})
I'm made a code ! I'm not sure if this works properly ! anyway it's not working on my app.
$scope.countdown = function() {
stopped = $timeout(function() {
console.log($scope.counter);
$scope.counter--;
$scope.countdown();
}, 1000);
};
Here is a simple countdown example:
HTML
<!doctype html>
<html ng-app>
<head>
<script src="http://code.angularjs.org/angular-1.0.0rc11.min.js"></script>
<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
</head>
<body>
<div ng-controller="CountdownController">
{{counter}}
</div>
</body>
</html>
Javascript
function CountdownController($scope,$timeout) {
$scope.counter = 60;
$scope.onTimeout = function(){
if ($scope.counter > 0) {
$scope.counter--;
mytimeout = $timeout($scope.onTimeout,1000);
} else {
$scope.counter = 60;
}
}
var mytimeout = $timeout($scope.onTimeout,1000);
}
Demo
'use strict';
var ngApp = angular.module('myApp', ['Test']);
var c1 = angular.module('Test', []);
c1.controller('Ctrl1', function ($scope, $timeout) {
$scope.coutDown = function () {
$scope.onTimeout = function () {
console.log("value", $scope.value);
$scope.value = $scope.value - 1;
return $scope.coutDown($scope.value);
};
var delay = $timeout($scope.onTimeout, 1000);
if ($scope.value < 1) {
$timeout.cancel(delay);
return true;
}
return false;
};
$scope.value = 5;
$scope.coutDown();
});
<div ng-app="myApp">
<div ng-controller="Ctrl1">
<h1>{{value}}</h1>
</div>
</div>
http://jsfiddle.net/pbxaD/49/
if you want to use $timeout you have to inject it. But why don't you just call the update method in a certain interval?
.controller('todaymatches', function($rootScope,$scope, $http, $interval) {
var update = function() {
$http.get("http://www.domaine.com/updatedjson/")
.success(function (response) {
$scope.matches = response;
});
};
var initialize = function() {
$interval(function() {
update();
}, 60 * 1000)
};
initialize();
})
I tried this for the count down and it seems to work.
app.controller('CountDownController', function($scope, $timeout) {
$scope.counter = 60;
$scope.countdown = function() {
if ($scope.counter === 0) {
// do your reload and execute here
//Just reset the counter if you just want it to count again
$scope.counter = 60;
return;
} else {
$timeout(function() {
console.log($scope.counter);
$scope.counter--;
$scope.countdown();
}, 1000);
}
};
$scope.countdown();
});
You could tie up the various things you want to do inside the if condition of the above code as commented. I just reset the counter after counting down to 0.
I coded the below directive for infinite scroll, my problem which I couldn't figure out why it just fire once when the directive is loaded, I need your advice on how to make my list infinite-scroll.
I'm using it to get data remotely and each time i'm calling it I add to the counter 25, so each time it would return more data.
Thanx,
angular.module('MyApp')
.controller('InboxCtrl', function($scope, InboxFactory) {
var counter = 0;
$scope.loadData = function() {
var promise = InboxFactory.getEvents(counter);
promise.then(function(result) {
$scope.events = result;
});
counter += 25;
};
});
angular.module('MyApp')
.factory('InboxFactory', function($http, $q) {
// Service logic
var defered = $q.defer();
function getUrl(count) {
return "api/inbox/get?request={'what':'Search','criteria':'inbox','criteriaId':null,'startTime':null,'endTime':null,'offset':" + count + ",'limit':25,'order':'event_time','direction':'DESC','source':''}";
}
function extract(result) {
return result.data.data;
}
// Public API here
return {
getEvents: function(count) {
$http.get(getUrl(count)).then(
function(result) {
defered.resolve(extract(result))
}, function(err) {
defered.reject(err);
}
);
return defered.promise;
}
};
});
angular.module('MyApp')
.directive('infiniteScroll', ['$timeout',
function(timeout) {
return {
link: function(scope, element, attr) {
var
lengthThreshold = attr.scrollThreshold || 50,
timeThreshold = attr.timeThreshold || 400,
handler = scope.$eval(attr.infiniteScroll),
promise = null,
lastRemaining = 9999;
lengthThreshold = parseInt(lengthThreshold, 10);
timeThreshold = parseInt(timeThreshold, 10);
if (!handler || !components.isFunction(handler)) {
handler = components.noop;
}
element.bind('scroll', function() {
var
remaining = element[0].scrollHeight - (element[0].clientHeight + element[0].scrollTop);
//if we have reached the threshold and we scroll down
if (remaining < lengthThreshold && (remaining - lastRemaining) < 0) {
//if there is already a timer running which has no expired yet we have to cancel it and restart the timer
if (promise !== null) {
timeout.cancel(promise);
}
promise = timeout(function() {
handler();
promise = null;
}, timeThreshold);
}
lastRemaining = remaining;
});
}
};
}
]);
<ul class="inbox-list" infinite-scroll="loadData()">
<li class="clearfix" ng-repeat="event in events">{{event}}</li>
</ul>
I Made some changes the more important is the use of ng-transclude and the creation of a new scope for the directive to pass the method and the parameters. You can have a look at the jsbind. Of course the data are hard coded so i could fake the behaviour.
<ul class="inbox-list" my-infinite-scroll composite-method="loadData()">
Given the following code, I'm finding that once the loadDetails function (the last one) is being triggered, the ID variable comes back undefined, as on the other functions is coming back correctly.
Did I miss something?
function Ctrl($scope, $http) {
var search = function(name) {
if (name) {
$http.get('http://api.discogs.com/database/search?type=artist&q='+ name +'&page=1&per_page=7', {ignoreLoadingBar: true}).
success(function(data3) {
$scope.clicked = false;
$scope.results = data3.results;
});
}
$scope.reset = function () {
$scope.sliding = false;
$scope.name = undefined;
}
}
$scope.$watch('name', search, true);
$scope.getDetails = function (id) {
$http.get('http://api.discogs.com/artists/' + id).
success(function(data) {
$scope.artist = data;
});
$http.get('http://api.discogs.com/artists/' + id + '/releases?page=1&per_page=8').
success(function(data2) {
$scope.releases = data2.releases;
});
$scope.$watch(function() {
return $scope.artist;
}, function() {
var pos = $scope.artist.name.toLowerCase().indexOf(', the');
if (pos != -1) {
$scope.artist.name = 'The ' + $scope.artist.name.slice(0, pos);
}
});
var _page = 0;
$scope.releases = [];
$scope.loadDetails = function(id) {
_page++;
console.log(_page);
$http.get('http://api.discogs.com/artists/' + id + '/releases?page=' + _page + '&per_page=12').then(function(data2) {
$scope.releases = data2.releases;
});
};
$scope.clicked = true;
$scope.sliding = true;
}
EDIT: Here's my view code:
<div class="infinite" infinite-scroll="loadDetails(artist.id)">
<div class="col-xs-3 col-md-3 release" ng-controller="ImageCtrl" release="release" ng-repeat="release in releases | filter:album | filter:year" the-directive position="{{ $index + 1 }}" last="{{ $last }}">
<img class="img-responsive" ng-src="{{image}}"/> {{release.title | characters:45}}
</div>
<div style='clear: both;'></div>
</div>
And the ng-Infinite-Scroll script that triggers the function when the containing div reaches the bottom:
/* ng-infinite-scroll - v1.0.0 - 2013-02-23 */
var mod;
mod = angular.module('infinite-scroll', []);
mod.directive('infiniteScroll', [
'$rootScope', '$window', '$timeout', function($rootScope, $window, $timeout) {
return {
link: function(scope, elem, attrs) {
var checkWhenEnabled, handler, scrollDistance, scrollEnabled;
$window = angular.element($window);
scrollDistance = 0;
if (attrs.infiniteScrollDistance != null) {
scope.$watch(attrs.infiniteScrollDistance, function(value) {
return scrollDistance = parseInt(value, 10);
});
}
scrollEnabled = true;
checkWhenEnabled = false;
if (attrs.infiniteScrollDisabled != null) {
scope.$watch(attrs.infiniteScrollDisabled, function(value) {
scrollEnabled = !value;
if (scrollEnabled && checkWhenEnabled) {
checkWhenEnabled = false;
return handler();
}
});
}
handler = function() {
var elementBottom, remaining, shouldScroll, windowBottom;
windowBottom = $window.height() + $window.scrollTop();
elementBottom = elem.offset().top + elem.height();
remaining = elementBottom - windowBottom;
shouldScroll = remaining <= $window.height() * scrollDistance;
if (shouldScroll && scrollEnabled) {
if ($rootScope.$$phase) {
return scope.$eval(attrs.infiniteScroll);
} else {
return scope.$apply(attrs.infiniteScroll);
}
} else if (shouldScroll) {
return checkWhenEnabled = true;
}
};
$window.on('scroll', handler);
scope.$on('$destroy', function() {
return $window.off('scroll', handler);
});
return $timeout((function() {
if (attrs.infiniteScrollImmediateCheck) {
if (scope.$eval(attrs.infiniteScrollImmediateCheck)) {
return handler();
}
} else {
return handler();
}
}), 0);
}
};
}
]);
rSo from what I read I understand you problem as in loadDetails() the id parameter is undefined. Where is loadDetails() called from? I assume its being called from the view. Are you passing this param in when it is being called? For ex:
<button ng-click="loadDetails('myId')">Load Details</button>
I would say your issue is you are not passing the param to this function. It would be helpful if you posted the view associated with this controller.