Angularjs Multiple Controllers, only the first one works - angularjs

I'm using angularjs 1.5.8 to basically mimic an excel table with equations. THere are three rows requiring two inputs that affect two outputs. I'm struggling on how to write my script to include multiple controllers as I'm building a controller for each row. If I comment out the second and third controller in my script, the first row works just fine. When no lines are commented, nothing works. I feel like I'm very close but not sure where I'm going wrong. Any help would be appreciated.
Here is the working controller:
angular.module('ADMApp', [])
.controller('ADMFarViewController', [function() {
var ctrl = this;
ctrl.ADMCalc = function() {
var ADMFarViewImgHeightvar = Number(ctrl.ADMFarViewImgHeightvar || 0);
var ADMFarViewVertPixvar = Number(ctrl.ADMFarViewVertPixvar || 0);
ctrl.ADM_FarViewFarthestViewer_ans = (ADMFarViewImgHeightvar * 3438) / ADMFarViewVertPixvar;
ctrl.ADM_FarViewViewRat_ans = ctrl.ADM_FarViewFarthestViewer_ans / ADMFarViewImgHeightvar;
}
}]);
Here is my plunker: https://plnkr.co/edit/6nKEPCeOqx7zEFx5M5WZ

Don't redefine your module every time.
// Code goes here
var ADMApp = angular.module('ADMApp', []);
ADMApp.controller('ADMFarViewController', [function() {
var ctrl = this;
ctrl.ADMCalc = function() {
var ADMFarViewImgHeightvar = Number(ctrl.ADMFarViewImgHeightvar || 0);
var ADMFarViewVertPixvar = Number(ctrl.ADMFarViewVertPixvar || 0);
ctrl.ADM_FarViewFarthestViewer_ans = (ADMFarViewImgHeightvar * 3438) / ADMFarViewVertPixvar;
ctrl.ADM_FarViewViewRat_ans = ctrl.ADM_FarViewFarthestViewer_ans / ADMFarViewImgHeightvar;
}
}]);
ADMApp.controller('ADMMinImgController', [function() {
var ctrl = this;
ctrl.ADMCalc = function() {
var ADM_MinImgHeightVertPix_var = Number(ctrl.ADM_MinImgHeightVertPix_var || 0);
var ADM_MinImgHeightFarthestViewer_var = Number(ctrl.ADM_MinImgHeightFarthestViewer_var || 0);
ctrl.ADM_MinImgHeightImageHeight_ans = (ADM_MinImgHeightVertPix_var * ADM_MinImgHeightFarthestViewer_var) / 3438;
ctrl.ADM_MinImgHeightViewRat_ans = ADM_MinImgHeightFarthestViewer_var / ctrl.ADM_MinImgHeightImageHeight_ans;
}
}]);
ADMApp.controller('ADMMaxImgController', [function() {
var ctrl = this;
ctrl.ADMCalc = function() {
var ADM_MaxImgImageHeight_var = Number(ctrl.ADM_MaxImgImageHeight_var || 0);
var ADM_MaxImgFarthestViewer_var = Number(ctrl.ADM_MaxImgFarthestViewer_var || 0);
ctrl.ADM_MaxImgVertPix_ans = (ADM_MaxImgImageHeight_var * 3438) / ADM_MaxImgFarthestViewer_var;
ctrl.ADM_MaxImgViewRat_ans = ADM_MaxImgFarthestViewer_var / ADM_MaxImgImageHeight_var;
}
}]);

angular.module('ADMApp', [])
That line of code defines the module 'ADMApp'. Since you hve this line three times in your code, you define the same module thrice, effectively overwriting its previous definition, containing the previously added controller.
Save it in a variable, or use angular.module('ADMApp')to get a reference to the previously defined module.

Related

Cannot save and show data from angular polling factory function only with $scope

I have a service with the following function below :
(function(){
angular.module('app.system')
.factory('Poller', function($http, $timeout) {
var data = {
eventObj: null,
spinner:false
};
var poller = function() {
$http.get('php file').then(function(r) {
var ev = r.data;
if(ev.length > 0)
{
data.eventObj = ev;
data.spinner = true;
if(ev.image != null && ev.image != "")
{
data.eventObj = ev;
}
}
else {
data.spinner = false;
}
$timeout(poller, 1000);
});
};
poller();
return {
data :data,
};
})()
This was my factory. In controller I do something like :
1 $scope.dataPoller = Poller.data;
2 var vm = this;
3 vm.event = Poller.data.event;
4 vm.spinner = Poller.data.spinner;
also at top of controller :
.run(function(Poller) {});
line 1- I see the ui change every 500ms
but line 2-4 don't update at all - only at the beginning for example the vm.event always empty buy in line 1 it does not
How can I solve it?
I need to update the data in the controller or another service and return to controller and update the view and the poller of course need to send new data every 500 ms
vm.event = Poller.data.event;
vm.spinner = Poller.data.spinner;
This is executed once, when your controller is created. It nitialized vm.event with the value that Poller.data.event has at this moment. Same for the spinner. Since the view displays vm.event, and since that value never changes, your view never changes.
Instead, use
vm.pollerData = Poller.data;
and in the view, use
{{ vm.pollerData.event }}
Every time an $http response comes back, angular will reevaluate the value of vm.pollerData.event, and since the value has changed, the view will update.

Angular to control printing , no. of times?

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();
}
}

AngularJS - Multiple Filters usage in controller

I want to use multiple filters in controller
Currently using
$filter('limitTo')($filter('lowercase')($filter('translate')('ACTIVE')), 5)
If we have more filters like this. How can I use multiple filters in controller rather conventional format like this?
You can simply introduce variables:
var limitTo = $filter('limitTo');
var lowercase = $filter('lowercase');
var translate = $filter('translate');
var filteredValue = limitTo(lowercase(translate('ACTIVE')), 5);
Or even
var lowercaseStatus = lowercase(translate('ACTIVE'));
var filteredValue = limitTo(lowercaseStatus, 5);
Another strategy would be to use the same syntax as in the view:
var filteredValue = $scope.$eval('"ACTIVE" | translate | lowercase | limitTo:5');
This is an interesting question. Usually you would do something like that or something like this:
var translatedValue = $filter('translate')('ACTIVE');
var lowercaseValue = $filter('lowercase')(translatedValue);
$scope.finalValue = $filter('limitTo')(lowercaseValue, 5)
I created a service inspired by this answer.
app.service('FilterChain',
['$filter', function($filter) {
var chain = {
value : '',
start : function(value) {
this.value = value;
return this;
},
applyFilter : function(filterName, args) {
args = args || [];
args.unshift(this.value);
this.value = $filter(filterName).apply(undefined, args)
return this;
}
};
return chain;
}]);
Usage is like this
$scope.value = FilterChain.start('Active')
.applyFilter('translate')
.applyFilter('limitTo', [5])
.applyFilter('uppercase')
.value;
You can use the service with other filters and objects such as arrays. See a working example here: JSFiddle

$compile within $compile not getting applied

I have a directive which takes in an array of container objects and $compiles a new container directive for each container and each nested container. It also compiles a resize handle before all containers except the first child. The link function looks like this:
//scope.dock is retrieved from a factory
scope.initContainers = function () {
var prevScope;
for (var i = 0; i < scope.dock.containers.length; i++) {
var newScope = scope.$new(true);
newScope.container = scope.dock.containers[i];
var newElement = '<panel-container class=\"' + scope.dock.containers[i].axis + '" ></panel-container>';
var newTemplate = $compile(newElement)(newScope);
if (i > 0) {
var sizerScope = scope.$new(true);
sizerScope.containerOne = prevScope;
sizerScope.containerTwo = newScope;
var sizerElement = '<resize-handle class=\"' + scope.dock.containers[i].axis + '"></resize-handle>';
var sizerTemplate = $compile(sizerElement)(sizerScope);
element.append(sizerTemplate);
}
element.append(newTemplate);
if (scope.dock.containers[i].containers.length > 0) {
generateContainers(scope.dock.containers[i], newScope, newTemplate);
}
}
return scope;
};
scope.sizeContainers = function () {
scope.$broadcast('size-containers');
};
var generateContainers = function (value, parentScope, parentElement) {
var prevScope;
for (var y = 0; y < value.containers.length; y++) {
var newChildScope = parentScope.$new(true);
newChildScope.container = value.containers[y];
var newChildElement = '<panel-container class=\"' + value.containers[y].axis + '" ></panel-container>';
var newChildTemplate = $compile(newChildElement)(newChildScope);
if (y > 0) {
var sizerScope = parentScope.$new(true);
sizerScope.containerOne = prevScope;
sizerScope.containerTwo = newChildScope;
var sizerElement = '<resize-handle class=\"' + value.containers[y].axis + '"></resize-handle>';
var sizerTemplate = $compile(sizerElement)(sizerScope);
parentElement.append(sizerTemplate);
}
parentElement.append(newChildTemplate);
if(typeof value.containers[y].containers !== 'undefined') {
if (value.containers[y].containers.length > 0) {
generateContainers(value.containers[y], newChildScope, newChildTemplate);
}
}
prevScope = newChildScope;
}
};
scope.initContainers().sizeContainers();
My problem is that the first child layer compiles but the second one does not. It does, however, work when I add scope.$apply to the end of generateContainers. Unfortunately for some reason it is skipping the first child element for each container and throwing a 'digest in progress' error.
Does anyone have any ideas on how to get this to compile?
And could someone explain why scope.$apply() is compiling the second layer only after I explicitly call it, even when $digest is already running?
I fixed this by getting rid of initContainers (since it was exactly the same as generateContainers) and moving that function to the container directive as well. That way the root directive wasn't trying to compile everything.

angularfire: Having trouble getting a Firebase array from my factory with $asArray()

I've got a factory that gets my data from Firebase, and I want my controller to be able to access it. However, when I console.log the data in my controller, it isn't the Array[10] that I would expect it to be, but rather an Array with keys 0,1,2,..10, $$added, $$error, $$moved,... and so on. However, when I skip out on using the factory, and use $asArray() method on my firebase ref directly in my controller it shows up nicely as an Array[10]
In my factory, this is what it looks like..
var listingsref = new Firebase("https://something.firebaseio.com");
var sync2 = $firebase(listingsref);
var products = sync2.$asArray();
factory.getProducts = function(){
return products;
};
Controller
$scope.products = marketFactory.getProducts();
console.log($scope.products) in my controller should be Array[10], but instead it's an Array with the data + a lot more $$ methods. Anyone know what's going on? Thanks
EDIT: Full Factory File
(function(){
var marketFactory = function($firebase){
var listingsref = new Firebase("https://something.firebaseio.com");
var sync2 = $firebase(listingsref);
var products = sync2.$asArray();
var factory = {};
factory.getProducts = function(){
console.log(products);
return products;
};
factory.getProduct = function(productId){
for(var x = 0; x<products.length ;x++){
if(productId == products[x].id){
return {
product:products[x],
dataPlace:x
};
}
}
return {};
};
factory.getNextProduct = function(productId, e){
var currentProductPlace = factory.getProduct(productId).dataPlace;
if (e=="next" && currentProductPlace<products.length){
return products[currentProductPlace+1];
}
else if(e=="prev" && currentProductPlace>0){
return products[currentProductPlace-1];
}
else{
return {};
}
};
factory.componentToHex = function(c){
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
};
factory.rgbToHex = function(r,g,b){
return "#" + factory.componentToHex(r) + factory.componentToHex(g) + factory.componentToHex(b);
};
factory.hexToRgb = function(hex) {
if(hex.charAt(0)==="#"){
hex = hex.substr(1);
}
var bigint = parseInt(hex, 16);
var r = (bigint >> 16) & 255;
var g = (bigint >> 8) & 255;
var b = bigint & 255;
return r + ", " + g + ", " + b;
};
factory.parseRgb = function(rgb){
rgb = rgb.replace(/\s/g, '');
var red = parseInt(rgb.split(',')[0]);
var green = parseInt(rgb.split(',')[1]);
var blue = parseInt(rgb.split(',')[2]);
return {
r:red,
g:green,
b:blue
};
};
return factory;
};
marketFactory.$inject = ['$firebase'];
angular.module('marketApp').factory('marketFactory', marketFactory);
}());
This snippet gets a synchronized AngulareFire array of products:
var products = sync2.$asArray();
The AngularFire documentation is a bit off on this point: what you get back from $asArray() is not an array, but the promise of an array. At some point in the future your products variable will contain an array. This is done because it may take (quite) some time for your array data to be downloaded from Firebase. Instead of blocking your code/browser while the data is downloading, it returns a wrapper object (called a promise) and just continues.
Such a promise is good enough for AngularJS: if you simply bind products to the scope and ng-repeat over it, your view will show all products just fine. This is because AngularFire behind the scenes lets AngularJS know when the data is available and Angular then redraws the view.
But you said:
console.log($scope.products) in my controller should be Array[10]
That is where you're mistaken. While AngularFire ensures that its $asArray() promise works fine with AngularJS, it doesn't do the same for console.log. So your console.log code runs before the data has been downloaded from Firebase.
If you really must log the products, you should wait until the promise is resolved. You this this with the following construct:
products.$loaded().then(function(products) {
console.log(products);
});
When you code it like this snippet, the data for your products will have been downloaded by the time console.log runs.
Note that the object will still have extra helper methods on it, such as $add. That is normal and also valid on an array. See the documentation for FirebaseArray for more information on what the methods are, what they're for an how to use them.
So I edited the code in the plnkr at http://plnkr.co/M4PqojtgRhDqU475NoRY.
The main differences are the following:
// Add $FirebaseArray so we can extend the factory
var marketFactory = function($firebase, $FirebaseArray){
var listingsref = new Firebase("https://something.firebaseio.com");
// Actually extend the AngularFire factory and return the array
var MarketFactory = $FirebaseArray.$extendFactory(factory);
return function() {
var sync = $firebase(listingsref, {arrayFactory: factory});
return sync.$asArray();
};
Check out https://www.firebase.com/docs/web/libraries/angular/guide.html#section-extending-factories for more information on extending AngularFire entries. You will likely need to make some adjustments to the rest of the factory code.

Resources