$interval is not allowing me to update my front end - javascript

I'm trying to create a landing page where the picture and accompanying caption updates, showing all of the images and captions in an array of objects (pictures with captions). I think it needs to use $interval or $timeout.
My JS that will show a single picture that does not update:
.controller('userCtrl', function ($scope, Auth, $location, $timeout) {
var Picture = Parse.Object.extend("Picture");
var query = new Parse.Query(Picture);
query.find({
success: function(pictures){
var x = pictures.length;
var getRandomImage = function () {
var imageCount = x
var index = Math.floor(
( Math.random() * imageCount * 2 ) % imageCount);
return( pictures[ index ] );
}
$scope.image = getRandomImage();
})
My JS that I think should work, creating a randomly scrolling line of pictures:
.controller('userCtrl', function ($scope, Auth, $location, $timeout) {
var Picture = Parse.Object.extend("Picture");
var query = new Parse.Query(Picture);
query.find({
success: function(pictures){
var x = pictures.length;
var getRandomImage = function () {
var imageCount = x
var index = Math.floor(
( Math.random() * imageCount * 2 ) % imageCount);
return( pictures[ index ] );
}
$scope.image = $timeout(function(){getRandomImage();}, 3000);
})
The key portion of my HTML:
<img id="logo" src= {{image.get('logo').url()}}>
<p>
This is a picture ${{image.get('caption')}}
</p>

You can move assigning inside interval func, and also you don't need create function getRandomImage on every callback, so you can try something like this
.controller('userCtrl', function ($scope, Auth, $location, $timeout) {
function getRandomImage(pictures) {
var imageCount = pictures.length,
index = Math.floor( ( Math.random() * imageCount * 2 ) % imageCount);
return( pictures[ index ] );
}
var Picture = Parse.Object.extend("Picture");
var query = new Parse.Query(Picture);
query.find({
success: function(pictures){
$interval(function(){$scope.image = getRandomImage(pictures);}, 3000);
}
});
}

This line:
$scope.image = $timeout(function(){getRandomImage();}, 3000);
is placing the return value of the $timeout call into the $scope.image variable, and that return value (as per the $timeout documentation) is a promise object.
Instead, you probably want to place the return value of the getRandomImage function into your image variable, after a certain timeout, like this:
$timeout(function(){$scope.image = getRandomImage();}, 3000);

Related

How to update a global variable inside a nested function in angularjs?

This is the code I am using. currentId is 10; I am making a service call which has a function of $http.get(to a JSON) and I want to attack the array in JSON's length to currentId after the function is executed. How do I do it? Is there any special function in angularjs which helps me. I have read the other relevant questions here, but I need this done in angularjs. Thanks.
var currentId = 10;
console.log(currentId + ' before function'); //outputs 10
function findId(){
readJson.readJsonfun().then(function(data) {
currentId = data.length; //say data.length = 20;
return currentId;
});}
findId();
console.log(currentId + ' before function'); //should output 20?
As it's Async function - use async approach
var currentId = 10;
var modifiedId1;
var modifiedId2;
console.log(currentId + ' before function call');
function findId(){
return readJson.readJsonfun().then(function(data) {
currentId = data.length;
return $q.when(currentId);
});
}
findId().then(function(id){
//first time we need it
firstFunction(currentId); //or firstFunction(id);
});
function firstFunction(id){
modifiedId1 = id * 2;
}
function secondFunction(){
return findId().then(function(id){
//second time we need it, currentId is updates
modifiedId2 = id * 4;
return $q.when();
});
}
Store the variable of concern (currentID) in the service. Inside your service, it would look something like this:
.service('Example', function(){
var service = this;
var currentID = null;
service.getCurrentID = function() {
return currentID;
}
service.findId(){
readJson.readJsonfun().then(function(data) {
currentId = data.length; //say data.length = 20;
});}
Then, from outside of the service, you could call Example.findID() to update the currentID, and then Example.getCurrentID() to retrieve the actual value

cannot set property of undefined angular js

I have a list of json objects, $scope.phones, and a folder full of json files with additional data about each phone. I am trying to iterate through the files to grab additional information to put in my list about each phone:
phonecatControllers.controller('PhoneListCtrl', ['$scope', 'Phone',
function($scope, Phone) {
$scope.phones = Phone.query();
var myTimer = window.setTimeout(function() {
for (var i = 0; i < $scope.phones.length; i++){
var weight = 0;
Phone.get({phoneId: $scope.phones[i].id}, function( phone) {
weight = phone.sizeAndWeight.weight;
$scope.phones[i].weight = weight;
});
};
} , 1000 );
$scope.orderProp = 'age';
}]);
The timer is so that the function doesn't run until after scope.phones is set, (I realize its a bit of a hack but its not causing issues.) I get an error cannot set property of undefined on:
$scope.phones[i].weight = weight;
If i try to access this outside of the .get method there isn't a problem, however the new value of weight does not exist outside of the get method.
wait for the list of phones before looping through them:
Phone.query().then(function(phones){
for(var i=0; i<phones.length; i++){
var weight = 0;
Phone.get({phoneId: phones[i].id}, function( phoneDetails) {
weight = phoneDetails.sizeAndWeight.weight;
phones[i].weight = weight;
});
}
}

AngularJS - orderBy distance function

I'm extremely new to AngularJS so go easy on me... :-) I am in the process of building a new PhoneGap app with Ionic Framework and AngularJS. I have a list of locations that outputs in a list view and a function that will look up the user's location and get the distance between their current location and the location in the list. These currently both work correctly and I can see my list, sort by normal fields (name, etc).
What I would like to do is to have a preferences screen where the user will be able to set their preferred sorting option. I have already setup my basic preference controller as well that currently only is storing the preference to sort by 'name' but I'd like it to sort by distance that is calculated by a function seen below. But since the distance function seems to be in this controller, I don't know how to make it sort by that? Do I need to make a filter that runs the distance function?
Again, I'm new so any help would be greatly appreciated!
Here is my controller:
.controller('LocationsCtrl', function($scope, $ionicLoading, $ionicPopup, LocationsService, SettingsService) {
$scope.locations = {};
$scope.navTitle = "List of Locations";
$scope.rightButtons = [{
type: 'button-icon button-clear ion-more',
tap: function(e) {
$scope.openSortModal();
}
}];
// Method called on infinite scroll
// Receives a "done" callback to inform the infinite scroll that we are done
$scope.loadMore = function() {
$timeout(function() {
// Placeholder for later
$scope.$broadcast('scroll.infiniteScrollComplete');
}, 1000);
}
$scope.loading = $ionicLoading.show({
content: 'Getting current location...',
showBackdrop: false
});
navigator.geolocation.getCurrentPosition(function(pos) {
var coords = $scope.currentLocation = [pos.coords.longitude, pos.coords.latitude];
$scope.locations = LocationsService.allSync();
$scope.sortLoc = SettingsService.get('sortLocBy');
$ionicLoading.hide();
}, function(error) {
$ionicPopup.alert({
title: 'Unable to get location: ' + error.message
}).then(function(res) {
$ionicLoading.hide();
// not working
});
});
$scope.distanceFromHere = function (_item, _startPoint) {
var start = null;
var radiansTo = function (start, end) {
var d2r = Math.PI / 180.0;
var lat1rad = start.latitude * d2r;
var long1rad = start.longitude * d2r;
var lat2rad = end.latitude * d2r;
var long2rad = end.longitude * d2r;
var deltaLat = lat1rad - lat2rad;
var deltaLong = long1rad - long2rad;
var sinDeltaLatDiv2 = Math.sin(deltaLat / 2);
var sinDeltaLongDiv2 = Math.sin(deltaLong / 2);
// Square of half the straight line chord distance between both points.
var a = ((sinDeltaLatDiv2 * sinDeltaLatDiv2) +
(Math.cos(lat1rad) * Math.cos(lat2rad) *
sinDeltaLongDiv2 * sinDeltaLongDiv2));
a = Math.min(1.0, a);
return 2 * Math.asin(Math.sqrt(a));
};
if ($scope.currentLocation) {
start = {
longitude: $scope.currentLocation[0],
latitude: $scope.currentLocation[1]
};
}
start = _startPoint || start;
var end = {
longitude: _item.location.lng,
latitude: _item.location.lat
};
var num = radiansTo(start, end) * 3958.8;
return Math.round(num * 100) / 100;
}
})
And here is my template:
<ion-view title="{{navTitle}}" left-buttons="leftButtons">
<ion-content header-shrink scroll-event-interval="5">
<ion-list class="locations-list">
<ion-item class="location-item" ng-repeat="loc in locations | orderBy:sortLoc" type="item-text-wrap" href="#/location/{{loc.id}}/details" style="background-image:url('{{loc.photos.0.url}}');">
<div class="location-title">
<p>{{loc.name}}</p>
<span class="distance-indicator"><span class="digit">{{distanceFromHere(loc)}}</span><span class="unit">mi</span></span>
</div>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
See the orderBy docs. As the orderBy expression, you can use a function which generates a value to use for sorting. All you should need to do is to put the distanceFromHere function in your sortLoc scope variable (or change the filter to orderBy:distanceFromHere).

AngularFire 0.5.0 $on 'change' event not firing correctly

Let's say I have a collection of articles I am trying to paginate through.
I'm using the $on("change") event to listen for changes to index and limit
.controller('articlesCtrl', ["$scope", "$firebase", "$stateParams", function($scope, $firebase, $stateParams) {
var limit = 2;
var index = $stateParams.id;
var articlesRef = new Firebase("https://example.firebaseio.com/articles").startAt(null, index).limit(limit);
var obj = $firebase(articlesRef);
obj.$on("change", function() {
var keys = obj.$getIndex();
index = keys[keys.length-1];
console.log(obj);
});
$scope.update = function(){
limit = limit + 2;
obj = $firebase(articlesRef.startAt(null, index).limit(limit));
}
}]);
What I'm noticing - is on initial load the $on("change") event fires twice.
And every subsequent call to update the index or limit does not fire the $on("change") event.
<button type="button" ng-click="update();">Update</button>
Each time $scope.update fires, you assign the obj variable to a new reference. However, you only attach obj.$on(change) to the original obj.
This could probably be optimized with some experimentation; here's a quick brute force to get you started:
var limit = 2;
var index = $stateParams.id;
var articlesRef = new Firebase("https://example.firebaseio.com/articles");
$scope.update = update;
update(); // initialize
function update(){
limit = limit + 2;
var obj = $firebase(articlesRef.startAt(null, index).limit(limit));
obj.$on("loaded", function() {
var keys = obj.$getIndex();
index = keys[keys.length-1];
console.log(obj);
});
}

Initialize Object with different parameters

Hello I have code which replaces document.write, makes a buffer and than pushes buffer into the document:
var lazyLoad = (function () {
var counter = 0
var buffer = new Array()
function work(options){
window.d = document
var tmp_buffer
d.write = d.writeln = function(s){ tmp_buffer += s}
d.open = d.close = function(){}
s = d.createElement('script')
s.setAttribute('type','text/javascript')
s.setAttribute('src',options.url)
d.getElementById(options.block).appendChild(s)
s.onload = function () {
buffer[counter] = tmp_buffer
console.log(buffer[1])
window.setTimeout(function() {
d.getElementById(options.block).innerHTML += buffer[counter]
}, 0)
counter++
}
}
return {
init: function (options) {
var CONFIG = {
url: '',
block: ''
}
$.extend(CONFIG, options)
random = $('#'+CONFIG.block).attr('rel')
id = $('#'+CONFIG.block).attr('id').replace(random,'')
id = id.replace('DIV','')
size = id.split('X')
ele_width = size[0] || CONFIG.width
ele_height = size[1] || CONFIG.height
$('#'+CONFIG.block).css({
'width':ele_width+'px',
'height':ele_height+'px'
})
$(window).load(function(){
if(options.adfox) {
random = $('#'+CONFIG.block).attr('id')
AdFox_getCodeScript(1, random, CONFIG.url)
}else{
work(options)
}
})
}
}
})();
If I init it once:
lazyLoad.init({
'http://test.com/test.js',
div1
})
But if I call it again with other parameters:
lazyLoad.init({
'http://test2.com/test.js',
div2
})
First init wont work. buffer will be empty. Where is my mistake?
I think that
$(window).load(function(){
will overwrite the event handler. Try using:
$(function(){
});
instead. I think it'll add an array of event handlers. I could be wrong though. Please let me know how it turns out.
Also, it doesn't look like you're defining "s" in the local scope. If you don't put "var" in front of a variable when you define it, it'll get created in the global scope.

Categories