Angular to control printing , no. of times? - angularjs

I do have a print Service developed using angular js,
Is there any efficient way that I can mention the no.of times.
Currently I can loop through this code and call n number of times
PrintService.printElement("printThisElement");
Print service code
function printElement(elem) {
var printSection = document.getElementById('printSection');
// if there is no printing section, create one
if (!printSection) {
printSection = document.createElement('div');
printSection.id = 'printSection';
document.body.appendChild(printSection);
}
var elemToPrint = document.getElementById(elem);
//clones the element you want to print
var domClone = elemToPrint.cloneNode(true);
printSection.innerHTML = '';
printSection.appendChild(elemToPrint);
$timeout(function(){
window.print();
}, 0);
window.onafterprint = function() {
printSection.innerHTML = '';
}
};
Can I loop thru this ?
$timeout(function(){
window.print();
}, 0);

Not sure of your question but from what I understand, your PrintService can be called from various controllers within your app. And you want to control the number of times this method can be called.
You can use a global variable, and check its value inside the PrintService.printElement("printThisElement"); method. If the value exceeds your limit, return an error.
var myApp = angular.module('myApp', []);
myApp.value('test', 0);
myApp.factory('PrintService ', ['test', function (test) {
this.printElement = function () {
//check 'test' value and then run print code
//test++ if printing
}
}]);

$timeout does not loops the function, $timeout used to execute the code inside it only once after a time out.
Instead use a variable to loop using if condition.
HEre is an example:
var count = 0;
function myFunction() {
count++;
if(count > 5)
{
return; // you can either return or execute any other code.
}
else
{
window.print();
}
}

Related

Doing basic validation in ionic

Hi Im trying my hands on ionic and angularjs. I have a sample code that deals with the phone-list. The working of the code is to add the phone number to the list and delete the selected and also when a number is entered it should check if the number exist there, if the number is not in existence then it should add it. The problem I face here is in checking the existence of the phone number in the list.
link
$scope.phonelist = [];
$scope.add = function() {
$scope.phonelist.push($scope.phone);
$scope.phone = {};
}
$scope.removeSelected = function() {
var i = $scope.phonelist.length;
// reversed loop because you change the array
while (i--) {
var phone = $scope.phonelist[i];
if (phone.checked) {
$scope.phonelist.splice(i, 1);
}
$scope.phonelist = [];
var added;
$scope.add = function() {
added = false;
for (var j=0;j<$scope.phonelist.length;j++) {
if (angular.equals($scope.phonelist[j], $scope.phone)) {
added=true;
}
}
if (!added) {
$scope.phonelist.push($scope.phone);
$scope.phone = {};
} else {
alert('error');
}
}
Update your controller like this for add function . Thanks

2 way binding issues with directives, controllers and services

This is bugging me a bit.
I have a service that handles logo panels and a function that is used to navigate between the different panels.
When getPanels is invoked it sets the currentPanel, index and length on the service when all promises have completed (see $q.all in the getPanels method):
.service('ConfiguratorLogoService', ['$q', 'UploadService', 'LogoService', 'ArrayService', 'SvgService', function ($q, uploadService, logoService, arrayService, helper) {
// Private function to build a file array
var _buildFileArray = function (panels, files) {
//--- Omitted for brevity ---//
};
// Create our service
var service = {
// Create our arrays
panels: [],
files: [],
currentPanel: null,
index: 0,
length: 0,
// Get our panels
getPanels: function (container, garmentId) {
// Create a deferred promise
var deferred = $q.defer();
// Create our arrays
var panels = []
files = [],
promises = [];
// If we have a container
if (container) {
// Get the containers children
var children = container.children()
// Loop through our panel's children
for (var i = 0; i < children.length; i++) {
// Get the current child
var child = angular.element(children[i]),
childId = child.attr('id'),
childTitle = helper.extractText(childId, ':', 1);
// Create our item
var panel = {
id: childId,
title: childTitle
};
// Try to get our item
promises.push(logoService.get(garmentId, panel.id).then(function (response) {
// If we have any data
if (response) {
// Add the file to our array
files.push(response);
}
}));
// Add our child to the array
panels.push(panel);
}
}
// After all the promises have been handled
$q.all(promises).then(function () {
// Get our files
service.files = _buildFileArray(panels, files);
service.panels = panels;
service.currentPanel = panels[0];
service.length = panels.length;
// Resolve our promise
deferred.resolve({
files: service.files,
panels: panels
});
});
// Return our promise
return deferred.promise;
},
// Get our next panel
navigateNext: function () {
// Create a deferred promise
var deferred = $q.defer();
// Get the next index or reset if we reached the end of our list
service.index = service.index === (service.length - 1) ? 0 : service.index += 1;
// Set our active panel
service.currentPanel = service.panels[service.index];
console.log(service.index);
// Resolve our promise
deferred.resolve();
// Return our promise
return deferred.promise;
},
// Get our previous panel
navigatePrevious: function () {
// Get the previous index or set to the end of our list
service.index = service.index === 0 ? service.length - 1 : service.index -= 1;
// Set our active panel
service.currentPanel = service.panels[service.index];
},
// Removes the file from azure
remove: function (index) {
//--- Omitted for brevity ---//
}
};
// Return our service
return service;
}])
which is fine, it works and the first panel is selected.
So, I have a controller, which is attached to a directive. The controller looks like this:
.controller('ConfiguratorLogosDirectiveController', ['ConfiguratorLogoService', 'RowService', function (service, rowService) {
var self = this;
// Set our current panel
self.currentPanel = service.currentPanel;
self.index = service.index;
self.length = service.length;
// Initialization
self.init = function (container, garmentId) {
// Get our panels
return service.getPanels(container, garmentId).then(function (response) {
self.panels = response.panels;
self.files = response.files;
// If we have any panels
if (self.panels.length) {
// Set our current panel
self.currentPanel = service.currentPanel;
self.index = service.index;
self.length = service.length;
}
// Return our response
return response;
})
};
// Map our service functions
self.upload = service.upload;
self.next = service.navigateNext;
self.previous = service.navigatePrevious;
self.remove = service.remove;
}])
As you can see, when I get my panels, I set the currentPanel, index and length on the controller itself which I didn't think I would have to do because when the controller is invoked, it already has a reference to the service values. I figured 2 way binding would come into play and when the service values update, the controller would update too.
Anyway, I update the values after the getPanels method completes successfully. In my directive I have this:
// Invoke on controller load
controller.init(container, scope.garmentId).then(function (response) {
// Map our properties
scope.panels = controller.panels;
scope.files = controller.files;
scope.currentPanel = controller.currentPanel;
scope.index = controller.index;
scope.length = controller.length;
});
which again works fine. In my template I can see the first panel and it looks fine.
So, then came the next step which was my navigate functions. I started with next which I have modified for testing purposes so I can output the controller.index as well as the console.log in the service navigation function.
The directive function looks like this:
scope.next = function () {
controller.next().then(function () {
console.log(controller.index);
});
};
When this method is invoked, I can see in my console that the service increases the index by 1 but the controller still shows 0 which means that 2 way binding is not working.
I am about to update my method in the controller to push the currentPanel and index to the controller, but before I do I thought I would ask here first.
So, does anyone know why my 2 way binding isn't working?
So my current workaround works, but I just don't like it.
In my directive I have done this:
scope.next = function () {
controller.next().then(function () {
console.log(controller.index);
scope.currentPanel = controller.currentPanel;
scope.index = controller.index;
scope.length = controller.length;
});
}
and in the directive controller I have done this:
self.next = function () {
// Try to navigate forward
return service.navigateNext().then(function () {
// Set our current panel
self.currentPanel = service.currentPanel;
self.index = service.index;
self.length = service.length;
console.log(self.index);
});
}
and in my service, it looks the same as before:
// Get our next panel
navigateNext: function () {
// Create a deferred promise
var deferred = $q.defer();
// Get the next index or reset if we reached the end of our list
service.index = service.index === (service.length - 1) ? 0 : service.index += 1;
// Set our active panel
service.currentPanel = service.panels[service.index];
console.log(service.index);
// Resolve our promise
deferred.resolve();
// Return our promise
return deferred.promise;
},
This works, but surely this is not the way it should work.
I have figured it out thanks to this article.
I just had to create an object in my directive and bind the values to that.
Doing that fixed the issues.

how to add parameter to the function in angular interval

I'm writing a function which will iterate through an array with some time interval.
eg:arr=[1,2,3,4,5,6,7]
And I want to show each element with angular interval.
$interval(step,5000,7);
function step(i){
console.log(arr[i]);
}
So it'll output the numbers inside the array in a 5 seconds' interval. How can I pass the parameter into the function? Thanks.
You could also do this way:
var arrOrig =[1,2,3,4,5,6,7],
arr = angular.copy(arrOrig), //if you want it for later
cancelPromise = $interval(step, 5000);
function step() {
console.log(arr.shift()); //take out the item from top of array
if (!arr.length) { //once array runs out
$interval.cancel(cancelPromise); //cancel interval
}
}
var arr = [1, 2, 3, 4, 5, 6, 7];
var $interval = angular.injector(['ng']).get('$interval');
var cancelPromise = $interval(step, 5000);
function step() {
console.log(arr.shift());
if (!arr.length) {
$interval.cancel(cancelPromise);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
arr.forEach(function (number, idx) {
$timeout(function () {
console.log(number);
}, 5000 * (idx + 1));
});
You want to use $timeout rather than $interval because calling $interval will set up an interval each time for each number and it won't stop until it's cleared explicitly.
var i=0;
$interval(function(){
step(i);
i++
},5000);
function step(i){
console.log(arr[i]);
}
This code will display the numbers one at a time, on repeat:
var getNextNumber = (function(){
var i = 0;
var numbers = [1,2,3,4,5,6,7];
return function(){
if(i >= numbers.length){
i = 0;
}
return numbers[i++];
};
})();
$interval(function(){
var number = getNextNumber();
console.log(number);
},5000);
See this working jsfiddle.
If you want to display them only once, use one of the $timeout solutions from one of the other answers. $interval is all about repeating some command for an indefinite amount of time, whereas $timeout is more about performing a command once in the future. See this answer for more.

binding to service variable, doesnt refresh (service changes the var frequently)

In my Service i have the vars i want to display and the getters for it:
var docsLoaded = 0;
var docsToLoad = null;
pouchService.getDocsLoaded = function () {
return docsLoaded;
};
pouchService.getDocsToLoad = function () {
return docsToLoad;
};
While the service is syncing, i want to count the synced docs
pouchService.syncNow = function () {
var foundLastSeq = false;
docsLoaded = 0;
docsToLoad = null;
remoteDB.info().then(function (remoteInfo) {
function findOutDiff(localPosition) {
docsToLoad = (remoteInfo.update_seq - localPosition) + 1;
console.log("docs to load: " + docsToLoad);
}
// start Sync progress
sync = localDB.sync(remoteDB, {live: false})
.on('change', function (info) {
console.log('AI change: ');
console.log(info);
if (info.direction === 'pull') {
if (foundLastSeq === false) {
foundLastSeq = true;
findOutDiff(info.change.last_seq);
}
}
console.log(docsLoaded + " from " + docsToLoad);
docsLoaded++;
})
In my HTML i want to display the progress like this:
{{pouchService.getDocsLoaded()}} from {{pouchService.getDocsToLoad()}}
Now i get sometimes a value from getDocsLoaded, but mostly its zero. When I cancel the Syncprogress i get the value where it's stopped.
So i get the value before it really starts and when it's over, but i want it during the sync progress. (on the console my my progressinfos are working as expected)
Any ideas?
The problem is in applying scope. Jim wrote a nice article about this problem:
jimhoskins.com/2012/12/17/angularjs-and-apply.html
Solved it:
$rootScope.$apply(function () {
docsLoaded++;
});

Cannot get iteration count of for loop cycle inside of the service result -> then

i have following method:
var i;
$scope.playAllSelectedSounds = function() {
try {
for( i; i < $scope.selectedSounds.length; i++) {
var fileName = $scope.selectedSounds[i].file;
var volume = $scope.selectedSounds[i].defaultVolume;
var filePath = "sounds/" +fileName+".mp3";
console.log(fileName);
MediaSrv.loadMedia(filePath).then(function(media){
console.log(media);
// !!!!!!!!!!! HERE I CANNOT GET value of the i VARIABLE
$scope.selectedSounds[i].state = 1;
// !!!!!!!!!!! HERE I CANNOT GET value of the i VARIABLE
$scope.selectedSounds[i].mediaInstance = media;
media.play();
media.setVolume(volume);
});
}
} catch(e) {
alert(JSON.stringify(e));
console.log(e);
$scope.showAlert("Error", "Error during the playing item");
}
};
Problem is that inside of the service:
MediaSrv.loadMedia(filePath).then(function(media){
I cannot get number o for cycle loop which i need to set in:
$scope.selectedSounds[i].state = 1;
Variable i is global i still cannot reach them. How can i solve it please?
It is not because i is not accessible, it is because i has run out of its limit because loadMedia is async and the value of i within the callback would become $scope.selectedSounds.length, since the for loop would have run out before the callback is invoked.
You could resolve this by using a closure variable representing the current item: You could just make use angular.forEach itself, and you don't event need to worry about accessing the right index. Instead just modify the object itself which is available as 1st argument of forEach evaluator function.
angular.forEach($scope.selectedSounds, function loadMedia(selectedSound, idx){
var fileName = selectedSound.file;
var volume = selectedSound.defaultVolume;
var filePath = "sounds/" +fileName+".mp3";
MediaSrv.loadMedia(filePath).then(function(media){
selectedSound.state = 1;
selectedSound.mediaInstance = media;
media.play();
media.setVolume(volume);
});
});
Also you forgot to initialize i in your case, which will cause your loop to not run at all.
Does it work if you create a local variable var that=i; just before your call to the promise, and then try to get "that" inside the promise return?
Otherwise try this :
for (var i in superarray){
(function(j) {
MyService.get(superarray[j].externalID).then(function(r) {
console.debug(j);
});
})(i);
}

Resources