Angularjs. Not set property without timeout - angularjs

I can't understand where is the problem.
I trying to display my form only when image is loaded, all works fine, except such annoying thing. When I'm trying to set $scope.show_image = true; without line $timeout(function(){}, 0); before, my form not appears.
<script type="text/javascript">
'use strict';
var app = angular.module('albumgallery', []);
app.factory('Photo', ['$http', '$rootScope', function($http, $rootScope) {
var photo;
function getPhoto() {
$http({method: 'GET', url: 'photoInfo'})
.success(function(data, status, headers, config) {
photo = data;
$rootScope.$broadcast('photo:loaded');
})
.error(function(data, status, headers, config) {
console.log(data);
});
}
getPhoto();
var service = {};
service.get = function() {
return photo;
}
return service;
}]);
function PhotoInfoCtrl($scope, $rootScope, $timeout, Photo) {
$rootScope.$on('photo:loaded', function() {
$scope.photo = Photo.get();
});
// -------------- MY PROBLEM --------------------
$rootScope.$on('image:loaded', function() {
$timeout(function(){}, 0);
$scope.show_image = true;
});
};
app.directive('imageonload', function factory($rootScope) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('load', function() {
$rootScope.$broadcast('image:loaded');
});
}
}
});
</script>
When I set timeout my form shows perfectly, but when i write only
$rootScope.$on('image:loaded', function() {
$scope.show_image = true;
});
something goes wrong and form not displayed. Please help understand my mistake.

Related

Angular.js Consuming Upload.progress event in a controller

I have a code that uploads documents in the controller, I wanted it to be moved to a service, so that other controllers can consume it.
"use strict";
angular.module('myApp')
.service('uploadDocumentService', ['Upload', function (Upload) {
this.UploadDocument = function ($file, data) {
Upload.upload({
url: '/uploadDocuments',
file: $file,
data: data
}).progress(function (evt) {
var progressReport = {};
progressReport.progressVisible = true;
progressReport.percentage = Math.round(evt.loaded / evt.total * 100);
return progressReport;
}).success(function (data, status, headers, config) {
var fileUploaded = {};
fileUploaded.id = data.id;
fileUploaded.name = data.fileName;
return fileUploaded;
});
}
}]);
I am unable to capture the .progress event in my controller
uploadDocumentService.UploadDocument($file, 'Path')
.progress(function (progressReport) {
//Some code
}).success(function (data) {
//Some code
});
Keep getting the error Cannot read property 'progress' of undefined
at m.$scope.uploadDocuments
Any tips on how to solve this problem, do I need to register the progress event in the service?
Controller code
"use strict";
angular.module('myApp')
.controller('controller', ['$scope', '$http', 'Upload', 'uploadDocumentService', function ($scope, $http, Upload, uploadDocumentService) {
$scope.uploadDocuments = function ($files) {
$scope.progressVisible = false;
for (var i = 0; i < $files.length; i++) {
var $file = $files[i];
uploadDocumentService.UploadDocument($file, 'path')
.progress(function (evt) {
$scope.progressVisible = true;
$scope.percentage = Math.round(evt.loaded / evt.total * 100);
}).success(function (data) {
var fileUploaded = {};
fileUploaded.id = data.id;
fileUploaded.name = data.fileName;
$scope.filesUploaded.push(fileUploaded);
$scope.isFileUploaded = true;
});
}]);
A colleague pointed out the mistake, the fix is as below, return was missing in the statement Upload.upload
"use strict";
angular.module('myApp')
.service('uploadDocumentService', ['Upload', function (Upload) {
this.UploadDocument = function ($file, data) {
return Upload.upload({
url: '/uploadDocuments',
file: $file,
data: data
}).progress(function (evt) {
}).success(function (data, status, headers, config) {
});
}
}]);
To achieve your expected result,add uploadDocumentService param in your controller function.
angular.module('myApp').controller("controller", function($scope, uploadDocumentService)

Disable Directive For particular function

I am using this directive to show 'loading' division on $http service request.
var module = angular.module('my-app', ['onsen', 'ngAnimate', 'ngMessages']);
module.directive('loading', ['$http', function ($http) {
return {
restrict: 'AE',
link: function ($scope, element, attrs, ctrl) {
$scope.isLoading = function () {
return ($http.pendingRequests.length > 0);
};
$scope.$watch($scope.isLoading, function (v) {
if (v) {
element.removeClass('ng-hide');
} else {
element.addClass('ng-hide');
}
});
}
};
<body ng-controller="BodyController">
<div loading class="spinner-container">
<img src="images/loading.svg" class="spinner" />
</div>
</body>
Want to disable it if this particular function is executing.
module.controller('BodyController', function ($scope, $http, $interval) {
$scope.getNotificationCount = function () {
var url="http://stackoverflow.com" // any url, stackoverflow is an example
var query = "";
$http({
method: 'POST',
url: url,
data: query,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).
success(function (data) {
console.log("success");
}).error(function (data) {
console.log("error");
});
};
$interval($scope.getNotificationCount,30000);
});
I want this because I am calling getNotificationCount() function in $interval() and I don't want to display this my custom loading html div on screen again n again.
Is there any way to achieve this? Help me.
module.directive('loading', ['$http', function ($http) {
return {
restrict: 'AE',
scope : {
isDisabled : '=' // Added new attribute to disable and enable the directive
},
link: function ($scope, element, attrs, ctrl) {
$scope.isLoading = function () {
return ($http.pendingRequests.length > 0);
};
$scope.$watch($scope.isLoading, function (v) {
if(!scope.isDisabled){
// Do things only when isDisabled property is false
if (v) {
element.removeClass('ng-hide');
} else {
element.addClass('ng-hide');
}
}
});
}
};
And your html code should be,
<body ng-controller="BodyController">
<div loading is-disabled="isLoaderDisabled" class="spinner-container">
<img src="images/loading.svg" class="spinner" />
</div>
</body>
Here, isLoaderDisabled is a scope variable. Now you can disable and enable your directive by just set true or false to your scope variable $scope.isLoaderDisabled.
$scope.isLoaderDisabled = false; // Initialize
module.controller('BodyController', function ($scope, $http, $interval) {
$scope.isLoaderDisabled = true; // disable your loading directive
$scope.getNotificationCount = function () {
var url="http://stackoverflow.com" // any url, stackoverflow is an example
var query = "";
$http({
method: 'POST',
url: url,
data: query,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).
success(function (data) {
console.log("success");
}).error(function (data) {
console.log("error");
$scope.isLoaderDisabled = false; // enable your directive
});
};
$interval($scope.getNotificationCount,30000);
});
You should enable your directive on each success function.

TypeError: Cannot set property 'highlight' of undefined angular-typeahead

I am trying to add angular-typeahead to my app for search suggestion taking help from this Plunkr.
This is the code of app.js file:
var myApp = angular.module('myApp', ['ngRoute','siyfion.sfTypeahead']);
myApp.factory('websitesSvc',function($http, $log, $q) {
return {
getwebsites: function(){
//Create a promise using promise library
var deferred = $q.defer();
$http({method: 'GET', url: '/api/websites/'}).
success(function(data, status, headers,config){
deferred.resolve(data);
}).
error(function(data, status, headers,config){
deferred.reject(status);
});
return deferred.promise;
}
};
});
myApp.controller('MyCtrl', ['$scope','websitesSvc','$timeout',
function($scope,websitesSvc,$timeout) {
$scope.searchString=null;
websitesSvc.getwebsites().then(function(websites){
$scope.websites = websites;
});
$timeout(function() {
var websites = new Bloodhound({
datumTokenizer: function(d) { return Bloodhound.tokenizers.whitespace(d.domain_name); },
queryTokenizer: Bloodhound.tokenizers.whitespace,
local:$scope.websites,
});
// initialize the bloodhound suggestion engine
websites.initialize();
$scope.numbersDataset = {
displayKey: 'domain_name',
source: websites.ttAdapter()
};
// Typeahead options object
$scope.exampleOptions = {
highlight: true
};
},1000);
}
]);
Adding delay so that the services are executed first and then the data fetched can be passed to typeahead for search suggestions.But I am getting following errors in console .
How should I change my code to debug this?

AngularJS Service Passing Data Between Controllers

When using an AngularJS service to try and pass data between two controllers, my second controller always receives undefined when trying to access data from the service. I am guessing this is because the first service does a $window.location.href and I'm thinking this is clearing out the data in the service? Is there a way for me to change the URL to a new location and keep the data persisted in the service for the second controller? When I run the code below the alert in the second controller is always undefined.
app.js (Where Service is Defined)
var app = angular.module('SetTrackerApp', ['$strap.directives', 'ngCookies']);
app.config(function ($routeProvider)
{
$routeProvider
.when('/app', {templateUrl: 'partials/addset.html', controller:'SetController'})
.when('/profile', {templateUrl: 'partials/profile.html', controller:'ProfileController'})
.otherwise({templateUrl: '/partials/addset.html', controller:'SetController'});
});
app.factory('userService', function() {
var userData = [
{yearSetCount: 0}
];
return {
user:function() {
return userData;
},
setEmail: function(email) {
userData.email = email;
},
getEmail: function() {
return userData.email;
},
setSetCount: function(setCount) {
userData.yearSetCount = setCount;
},
getSetCount: function() {
return userData.yearSetCount;
}
};
});
logincontroller.js: (Controller 1 which sets value in service)
app.controller('LoginController', function ($scope, $http, $window, userService) {
$scope.login = function() {
$http({
method : 'POST',
url : '/login',
data : $scope.user
}).success(function (data) {
userService.setEmail("foobar");
$window.location.href = '/app'
}).error(function(data) {
$scope.login.error = true;
$scope.error = data;
});
}
});
appcontroller.js (Second controller trying to read value from service)
app.controller('AppController', function($scope, $http, userService) {
$scope.init = function() {
alert("In init userId: " userService.getEmail());
}
});
Define your service like this
app.service('userService', function() {
this.userData = {yearSetCount: 0};
this.user = function() {
return this.userData;
};
this.setEmail = function(email) {
this.userData.email = email;
};
this.getEmail = function() {
return this.userData.email;
};
this.setSetCount = function(setCount) {
this.userData.yearSetCount = setCount;
};
this.getSetCount = function() {
return this.userData.yearSetCount;
};
});
Check out Duncan's answer here:
AngularJS - what are the major differences in the different ways to declare a service in angular?

Return factory data to controller always undefined

Trying to return data from the factory and logging within the factory outputs the correct data, but once passed to the controller it is always undefined. If I have my factory logic inside the controller it will work fine. So it must be something simple Im missing here?
Application
var app = angular.module('app', []);
app.controller('animalController', ['$log', '$scope', 'animalResource', function($log, $scope, animalResource) {
$scope.list = function() {
$scope.list = 'List Animals';
$scope.animals = animalResource.get(); // returns undefined data
$log.info($scope.animals);
};
$scope.show = function() {};
$scope.create = function() {};
$scope.update = function() {};
$scope.destroy = function() {};
}]);
app.factory('animalResource', ['$http', '$log', function($http, $log) {
return {
get: function() {
$http({method: 'GET', url: '/clusters/xhrGetAnimals'}).
success(function(data, status, headers, config) {
//$log.info(data, status, headers, config); // return correct data
return data;
}).
error(function(data, status, headers, config) {
$log.info(data, status, headers, config);
});
},
post: function() {},
put: function() {},
delete: function() {}
};
}]);
Log Info
[Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
200 function (name) {
if (!headersObj) headersObj = parseHeaders(headers);
if (name) {
return headersObj[lowercase(name)] || null;
}
return headersObj;
} Object {method: "GET", url: "/clusters/xhrGetAnimals"}
Your get() method in service is not returning anything. The return inside the success callback only returns from that particular function.
return the $http object
Che this example that is how you use the promises and you return the factory then you access the methods injecting the service on your controller
Use dot syntax to access the function you define on the service
'use strict';
var app;
app = angular.module('app.formCreator.services', []);
app.factory('formCreatorService', [
'$http', '$q', function($http, $q) {
var apiCall, bjectArrarContainer, deferred, factory, webBaseUrl, _getFormElementsData;
factory = {};
deferred = $q.defer();
bjectArrarContainer = [];
webBaseUrl = 'https://tools.XXXX_url_XXXXX.com/XXXXXXX/';
apiCall = 'api/XXXXX_url_XXXX/1000';
_getFormElementsData = function() {
$http.get(webBaseUrl + apiCall).success(function(formElements) {
deferred.resolve(formElements);
}).error(function(err) {
deferred.reject(error);
});
return deferred.promise;
};
factory.getFormElementsData = _getFormElementsData;
return factory;
}
]);
then do it like this for example
'use strict';
var app;
app = angular.module('app.formCreator.ctrls', []);
app.controller('formCreatorController', [
'formCreatorService', '$scope', function(formCreatorService, $scope) {
$scope.formElementsData = {};
formCreatorService.getFormElementsData().then(function(response) {
return $scope.formElementsData = response;
});
}
]);

Resources